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

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

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

引子

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

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

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

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

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

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

C++11

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

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

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

示例 1: 未加括號(hào)標(biāo)識(shí)符表達(dá)式

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

示例 2: 加括號(hào)的標(biāo)識(shí)符表達(dá)式

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

示例3:未加括號(hào)的類成員訪問(wèn)

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

示例4:加括號(hào)的類成員訪問(wèn)

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)用對(duì)象表達(dá)式

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: 右值表達(dá)式

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

示例8:右值引用變量

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

C++14

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

放寬對(duì)不完整類型的限制

C++11標(biāo)準(zhǔn)要求decltype在使用時(shí),推導(dǎo)的表達(dá)式必須是完整類型。如果decltype推導(dǎo)的表達(dá)式是一個(gè)不完整類型,例如某個(gè)類的聲明但尚未定義,那么會(huì)導(dǎo)致編譯錯(cuò)誤。C++14對(duì)這個(gè)限制進(jìn)行了放寬,允許使用decltype推導(dǎo)不完整類型的變量。這使得編寫一些特定的模板代碼更加方便,因?yàn)樵谀承┣闆r下,可能需要推導(dǎo)出不完整類型。

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

以下是一個(gè)示例,演示如何在泛型編程中使用 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)

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

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

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

示例 1:標(biāo)識(shí)符表達(dá)式

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

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

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

示例 3:左值表達(dá)式

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

示例4:右值表達(dá)式

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)作為一種返回類型的語(yǔ)法。它用于在函數(shù)聲明中指定返回類型,該返回類型將從函數(shù)體中的表達(dá)式推導(dǎo)而來(lái)。

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

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

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

第二種:C++14 基于auto和decltype實(shí)現(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)實(shí)現(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;

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

C++17

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

template<decltype(auto) n>  // C++17 decltype(auto)形參聲明
auto f() -> std::pair<decltype(n), decltype(n)> // auto 不能從花括號(hào)初始化器列表推導(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之前,下述代碼無(wú)法編譯通過(guò),而在C++20中則可以編譯通過(guò)。

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

總結(jié)

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

相關(guān)文章

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

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

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

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

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

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

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

    淺析C語(yǔ)言中的sizeof

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

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

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

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

    C語(yǔ)言中分為單行注釋和多行注釋:?jiǎn)涡凶⑨?以?//?開(kāi)始的這一行文本,可能不被編譯器所支持;多行注釋從?/*?到?*/之間的所有文本,不支持嵌套,下面讓我們?cè)敿?xì)來(lái)了解
    2022-04-04
  • C++實(shí)現(xiàn)自定義撤銷重做功能的示例代碼

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

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

    C語(yǔ)言實(shí)現(xiàn)任意進(jìn)制轉(zhuǎn)換器

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

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

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

    C++?二進(jìn)制文件讀寫方式及示例詳解

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

最新評(píng)論

博白县| 东明县| 富顺县| 平谷区| 虹口区| 延川县| 丹江口市| 阜南县| 桦川县| 凭祥市| 依兰县| 嘉定区| 南汇区| 加查县| 德惠市| 富锦市| 中宁县| 贡嘎县| 静乐县| 嘉兴市| 屏东县| 舟山市| 天峨县| 高雄市| 元阳县| 囊谦县| 峨眉山市| 绥宁县| 横山县| 赤城县| 专栏| 道孚县| 东平县| 阿拉善左旗| 永年县| 克拉玛依市| 灵丘县| 东台市| 凌海市| 任丘市| 名山县|