最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解C++17中的decltype類型推導(dǎo)

 更新時間:2023年06月26日 09:58:54   作者:@一鳴驚人  
這篇文章主要介紹了C++17中的decltype類型推導(dǎo),本文從泛型編程中經(jīng)常會遇到2個常見問題入手,循序漸進的分析了從C++11開始引入的關(guān)鍵字decltype,需要的朋友可以參考下

引子

在編程過程中,有時我們需要根據(jù)表達式的類型來聲明變量,尤其是在涉及模板編程和泛型編程時,經(jīng)常會遇到這樣的問題:(1)、有些泛型類型由模板參數(shù)決定,但是卻很難或根本無法表示;(2)、需要在編譯時確定變量的類型。

除此之外,我們知道auto在自動類型推導(dǎo)時,會忽略類型的修飾符。如此會導(dǎo)致auto推導(dǎo)的類型會與原表達式的類型存在不一致問題。

為了更好的解決這些問題,從C++11標(biāo)準(zhǔn)開始,C++引入了decltype關(guān)鍵字,其作用是讓編譯器在編譯時識別表達式的類型,方便的的進行類型推導(dǎo),同時也解決泛型編程和模板編程中變量類型表示的問題。

標(biāo)準(zhǔn)演進

decltype是declare type的縮寫。C++11標(biāo)準(zhǔn)引入了decltype的核心功能和推導(dǎo)規(guī)則,C++11以后的各標(biāo)準(zhǔn)都本別對C++11自定的規(guī)則進行擴容和改進。具體演進過程如下所示:

  • C++11:引入關(guān)鍵字,并引入decltype的核心功能,用于根據(jù)表達式推導(dǎo)出變量的類型;
  • C++14:引入兩個重要改進
  • 引入decltype(auto)語法,此語法可用于函數(shù)返回值類型的推導(dǎo)?;赿ecltype(auto)語法,函數(shù)的返回值類型可通過函數(shù)體的返回值表達式來推導(dǎo),從而簡化函數(shù)返回值類型的聲明。
  • 放寬了對不完整類型的限制:在 C++11 中,如果 decltype 推導(dǎo)的表達式結(jié)果是一個不完整類型,那么會導(dǎo)致編譯錯誤。而在 C++14 中,對不完整類型的處理更加寬松,允許使用decltype 推導(dǎo)不完整類型的變量。
  • C++17:decltype(atuo)支持非類型模板形參占位符。

C++11

引入關(guān)鍵字,并引入decltype的核心功能,用于根據(jù)表達式推導(dǎo)出變量的類型;當(dāng)使用decltype(e) 推導(dǎo)表達式 e(類型為T)的類型時,C++11標(biāo)準(zhǔn)定義decltype的推導(dǎo)規(guī)則如下:

  • 如果是一個未加括號的標(biāo)識符表達式或類成員訪問,那么decltype(e)的推導(dǎo)結(jié)果為e類型T;假如不存在這樣的實體或e是一組重載函數(shù),那么decltype(e)無法推導(dǎo)。而且推導(dǎo)過程const/volatile 限定符會被忽略;
  • 如果e是一個可調(diào)用對象,那么decltype(e)推導(dǎo)為可調(diào)用對象返回值的類型;
  • 如果e是一個左值,decltype(e)推導(dǎo)為T&。const/volatile 限定符不能忽略;
  • 如果e是一個將亡值,decltype(e)推導(dǎo)為T&&,const/volatile 限定符不可忽略;
  • 如decltype(e)無法命中上述4情況,decltype(e)將會推導(dǎo)為e的類型T;

為了讓大家更形象的理解這5條規(guī)則,下面我們通過一些示例來說明這五條推導(dǎo)規(guī)則。

示例 1: 未加括號標(biāo)識符表達式

int x = 42;
decltype(x) y; // 推導(dǎo)結(jié)果是 int,滿足第1條規(guī)則

示例 2: 加括號的標(biāo)識符表達式

int x = 42;
decltype((x)) y = x; // 推導(dǎo)結(jié)果是 int&,滿足第三條規(guī)則

示例3:未加括號的類成員訪問

struct MyClass {
    int member;
};
const MyClass obj;
decltype(obj.member) result = obj.member; // 推導(dǎo)結(jié)果是 int, 忽略const/volatile 限定符,滿足第1條規(guī)則

示例4:加括號的類成員訪問

struct MyClass {
    int member;
};
const MyClass obj;
decltype((bj.member)) result = obj.member; // 推導(dǎo)結(jié)果是 const int&, const/volatile 限定符不能忽略,滿足第3條規(guī)則

示例 5: 可調(diào)用對象表達式

int add(int a, int b)
{
    return a + b;
}
decltype(add(1, 2)) result; // 推導(dǎo)結(jié)果是 int,滿足第2條規(guī)則

示例 6: 將亡值

int x = 42;
decltype(std::move(x)) result = std::move(x); // 推導(dǎo)結(jié)果為int&&,std::move(x) 為將亡值

示例 7: 右值表達式

int x = 42;
decltype(x + 1) result; // 推導(dǎo)結(jié)果是 int(右值表達式 x + 1 的類型是 int)

示例8:右值引用變量

int&& i = 500;
decltype(i) x2;           // x2的類型是int&&,滿足第5條

C++14

C++14主要引進了兩個重要改進,他們分別是:放寬對不完整類型的限制;引入decltype(auto)語法。

放寬對不完整類型的限制

C++11標(biāo)準(zhǔn)要求decltype在使用時,推導(dǎo)的表達式必須是完整類型。如果decltype推導(dǎo)的表達式是一個不完整類型,例如某個類的聲明但尚未定義,那么會導(dǎo)致編譯錯誤。C++14對這個限制進行了放寬,允許使用decltype推導(dǎo)不完整類型的變量。這使得編寫一些特定的模板代碼更加方便,因為在某些情況下,可能需要推導(dǎo)出不完整類型。

但是,雖然C++14放寬了對不完整類型的限制,但仍然要求推導(dǎo)的表達式在使用時必須是可見的,即需要在推導(dǎo)時至少對類型進行了前向聲明。否則,將會導(dǎo)致編譯錯誤。

以下是一個示例,演示如何在泛型編程中使用 decltype 推導(dǎo)不完整類型:

template <typename T>
struct Container
{
    using ValueType = decltype(*std::declval<T>()); // 使用 decltype 推導(dǎo)不完整類型
    // 其他成員和函數(shù)...
};
int main()
{
    Container<std::vector<int>> container;
    using ValueType = typename decltype(container)::ValueType; // 推導(dǎo)結(jié)果為 int&
    return 0;
}

decltype(auto)

除了放寬對不完整類型的限制,C++14還有一個特色就是decltype(auto)。decltype(auto)作用是告訴編譯器auto的推導(dǎo)規(guī)則遵循decltype而非auto。不過有一點需要注意就是decltype(auto)必須單獨聲明,不能與其他相結(jié)合。所以下述聲明是不合法的:decltype(auto)*,const decltype(auto), volatile decltype(auto)。

decltype(auto) 的推導(dǎo)規(guī)則如下:

  • 如果初始化表達式是一個標(biāo)識符表達式,那么decltype(auto)推導(dǎo)為表達式的類型(const/volatile 限定符和引用修飾符不能忽略);
  • 如果初始化表達式是一個函數(shù)調(diào)用表達式,那么decltype(auto)推導(dǎo)為函數(shù)調(diào)用表達式的返回類型;
  • 如果初始化表達式是一個左值表達式(如變量名、數(shù)組名、成員訪問等),那么decltype(auto)推導(dǎo)為對應(yīng)左值類型的引用類型(const/volatile 限定符和引用修飾符不能忽略)。
  • 如果初始化表達式是一個右值表達式(如字面值、臨時對象、表達式的結(jié)果等),那么decltype(auto)推導(dǎo)為對應(yīng)右值的類型(const/volatile 限定符和引用修飾符不能忽略)。
  • 如果初始化表達式是一個將亡值(如移動賦值),那么decltype(auto)推導(dǎo)為對應(yīng)類型的右值引用

示例 1:標(biāo)識符表達式

int x = 42;
decltype(auto) y = x; // 推導(dǎo)結(jié)果是 int(x 的類型)

示例 2:函數(shù)調(diào)用表達式

int add(int a, int b)
{
    return a + b;
}
decltype(auto) result = add(1, 2); // 推導(dǎo)結(jié)果是 int(add 函數(shù)返回類型)

示例 3:左值表達式

const int x = 42;
decltype(auto) ref = (x); // 推導(dǎo)結(jié)果是 const int&(x 的引用類型)

示例4:右值表達式

decltype(auto) x2 = 50; // 推導(dǎo)結(jié)果是 int

示例4:將亡值

int x2 = 50;
decltype(auto) x3 = std::move(x2); // 推導(dǎo)結(jié)果為int&&

除了變量類型推導(dǎo)以外,在C++14中引入了decltype(auto)作為一種返回類型的語法。它用于在函數(shù)聲明中指定返回類型,該返回類型將從函數(shù)體中的表達式推導(dǎo)而來。

為了更好的理解decltype(auto)作為一種返回類型的語法,我們參考下面三種函數(shù)返回類型自動推導(dǎo)定義方式。

第一種: C++14 基于auto新特性返回值類型自動推導(dǎo)

template<typename Container, typename Index>
auto accessOrUpdate(Container& c, Index i) { 
  return c[i];  // 返回類推導(dǎo)為c[i]的類型,而且會異常引用限制      
}
std::vector<int> v{1,2,3,4,5};
accessOrUpdate(v,2) = 10;      // 編譯錯誤,不允許賦值

第二種:C++14 基于auto和decltype實現(xiàn)返回值類型推導(dǎo)

template <typename Container, typename Index>
auto accessOrUpdate(Container &c, Index i) -> decltype(c[i]) {
  return c[i];
}
std::vector<int> v{1,2,3,4,5};
accessOrUpdate(v,2) = 10;

第三種:C++14 decltype(auto)實現(xiàn)返回值類型推導(dǎo)

template <typename Container, typename Index>
decltype(auto) accessOrUpdate(Container &c, Index i) {
  return c[i];
}
std::vector<int> v{1,2,3,4,5};
accessOrUpdate(v,2) = 10;

對比上述三種函數(shù)返回值類型推導(dǎo),decltype(auto)可讓編譯器根據(jù)表達式的類型自動推導(dǎo)函數(shù)的返回類型,而不需要顯式地指定返回類型。這種方式可簡化代碼,而且推導(dǎo)更加靈活。

C++17

為與auto交相輝映,C++17開始支持decltype(auto)非類型模板。但是需特別注意的是在C++17標(biāo)準(zhǔn)中,非類型模板參數(shù)類型必須是整理類型(int, short, long等),枚舉類型,指針類型,左值引用類型和std::nullptr_t,而自定義類型,浮點數(shù)和字符串則不允許作非類型模板參數(shù)。

template<decltype(auto) n>  // C++17 decltype(auto)形參聲明
auto f() -> std::pair<decltype(n), decltype(n)> // auto 不能從花括號初始化器列表推導(dǎo)
{
    return {n, n};
}
f<5>();      // n為int
f<(5)>();    // n為int&
f<'a'>();    // n為char
f<('a')>();  // n為char&
f<1.0>();    // 編譯失敗double不能作為模板參數(shù),double不允許做非類型模板參數(shù)。

C++20允許字面量類類型作為非類型模板參數(shù)。例如在C++20之前,下述代碼無法編譯通過,而在C++20中則可以編譯通過。

class A {};
template <A a>
class B {};
A a;
B<a> b;  // C++20 前編譯失敗,C++20 可以編譯成功。

總結(jié)

本文從泛型編程中經(jīng)常會遇到2個常見問題入手,循序漸進的分析了從C++11開始引入的關(guān)鍵字decltype,希望本文可以對大家有所幫助。

相關(guān)文章

  • C++常量詳解二(常量形參,常量返回值,常量成員函數(shù))

    C++常量詳解二(常量形參,常量返回值,常量成員函數(shù))

    這篇文章主要介紹了C++常量詳解二(常量形參,常量返回值,常量成員函數(shù)),需要的朋友可以參考下
    2017-06-06
  • c++從函數(shù)返回數(shù)組的方法代碼

    c++從函數(shù)返回數(shù)組的方法代碼

    在本篇文章里小編給大家整理的是關(guān)于c++從函數(shù)返回數(shù)組的方法代碼,有興趣的朋友們可以學(xué)習(xí)參考下。
    2020-02-02
  • 深入理解結(jié)構(gòu)體中占位符的用法

    深入理解結(jié)構(gòu)體中占位符的用法

    本篇文章是對結(jié)構(gòu)體中占位符的用法進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • 淺析C語言中的sizeof

    淺析C語言中的sizeof

    sizeof是C/C++中的一個操作符(operator),作用就是返回一個對象或者類型所占的內(nèi)存字節(jié)數(shù)。返回值類型為size_t,在頭文件stddef.h中定義
    2013-07-07
  • C++ 整數(shù)拆分方法詳解

    C++ 整數(shù)拆分方法詳解

    整數(shù)拆分,指把一個整數(shù)分解成若干個整數(shù)的和。本文重點給大家介紹C++ 整數(shù)拆分方法詳解,非常不錯,感興趣的朋友一起學(xué)習(xí)吧
    2016-08-08
  • 介紹C語言程序中的注釋等輔助語句如何使用

    介紹C語言程序中的注釋等輔助語句如何使用

    C語言中分為單行注釋和多行注釋:單行注釋?以?//?開始的這一行文本,可能不被編譯器所支持;多行注釋從?/*?到?*/之間的所有文本,不支持嵌套,下面讓我們詳細來了解
    2022-04-04
  • C++實現(xiàn)自定義撤銷重做功能的示例代碼

    C++實現(xiàn)自定義撤銷重做功能的示例代碼

    在使用c++做界面開發(fā)的時候,尤其是實現(xiàn)白板功能時需要自己實現(xiàn)一套撤銷重做功能.如果是qt則有QUndoable對象,可以直接拿來用。但是如果是使用gdi繪圖,則可能需要自己實現(xiàn)了。本文就來用C++實現(xiàn)自定義撤銷重做功能,需要的可以參考一下
    2022-12-12
  • C語言實現(xiàn)任意進制轉(zhuǎn)換器

    C語言實現(xiàn)任意進制轉(zhuǎn)換器

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)任意進制轉(zhuǎn)換器,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C++?list常用接口和模擬實現(xiàn)實例代碼

    C++?list常用接口和模擬實現(xiàn)實例代碼

    C++中l(wèi)ist容器底層實現(xiàn)是使用帶頭雙向循環(huán)鏈表的結(jié)構(gòu),通過指針指向前一個和后一個節(jié)點,它也具有雙向鏈表的優(yōu)缺點,下面給大家介紹C++?list常用接口和模擬實現(xiàn)代碼,感興趣的朋友一起看看吧
    2025-04-04
  • C++?二進制文件讀寫方式及示例詳解

    C++?二進制文件讀寫方式及示例詳解

    這篇文章主要為大家介紹了C++?二進制文件讀寫實現(xiàn)方式及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04

最新評論

天镇县| 许昌县| 澎湖县| 韩城市| 鹿泉市| 潢川县| 西峡县| 唐山市| 安溪县| 区。| 车险| 闸北区| 海淀区| 铜陵市| 眉山市| 苗栗市| 郁南县| 青州市| 嘉鱼县| 蓬溪县| 海丰县| 游戏| 舟曲县| 清远市| 厦门市| 新邵县| 旌德县| 宁国市| 柞水县| 墨竹工卡县| 新余市| 若尔盖县| 开封市| 南宫市| 余庆县| 石屏县| 汝州市| 万安县| 曲麻莱县| 汨罗市| 合阳县|