欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

引子

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

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

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

標(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)都本別對C++11自定的規(guī)則進(jìn)行擴(kuò)容和改進(jìn)。具體演進(jìn)過程如下所示:

  • C++11:引入關(guān)鍵字,并引入decltype的核心功能,用于根據(jù)表達(dá)式推導(dǎo)出變量的類型;
  • C++14:引入兩個(gè)重要改進(jìn)
  • 引入decltype(auto)語法,此語法可用于函數(shù)返回值類型的推導(dǎo)?;赿ecltype(auto)語法,函數(shù)的返回值類型可通過函數(shù)體的返回值表達(dá)式來推導(dǎo),從而簡化函數(shù)返回值類型的聲明。
  • 放寬了對不完整類型的限制:在 C++11 中,如果 decltype 推導(dǎo)的表達(dá)式結(jié)果是一個(gè)不完整類型,那么會導(dǎo)致編譯錯(cuò)誤。而在 C++14 中,對不完整類型的處理更加寬松,允許使用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è)未加括號的標(biāo)識符表達(dá)式或類成員訪問,那么decltype(e)的推導(dǎo)結(jié)果為e類型T;假如不存在這樣的實(shí)體或e是一組重載函數(shù),那么decltype(e)無法推導(dǎo)。而且推導(dǎo)過程const/volatile 限定符會被忽略;
  • 如果e是一個(gè)可調(diào)用對象,那么decltype(e)推導(dǎo)為可調(diào)用對象返回值的類型;
  • 如果e是一個(gè)左值,decltype(e)推導(dǎo)為T&。const/volatile 限定符不能忽略;
  • 如果e是一個(gè)將亡值,decltype(e)推導(dǎo)為T&&,const/volatile 限定符不可忽略;
  • 如decltype(e)無法命中上述4情況,decltype(e)將會推導(dǎo)為e的類型T;

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

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

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

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

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)用對象表達(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),他們分別是:放寬對不完整類型的限制;引入decltype(auto)語法。

放寬對不完整類型的限制

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

但是,雖然C++14放寬了對不完整類型的限制,但仍然要求推導(dǎo)的表達(dá)式在使用時(shí)必須是可見的,即需要在推導(dǎo)時(shí)至少對類型進(jìn)行了前向聲明。否則,將會導(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)

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

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

  • 如果初始化表達(dá)式是一個(gè)標(biāo)識符表達(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ù)組名、成員訪問等),那么decltype(auto)推導(dǎo)為對應(yīng)左值類型的引用類型(const/volatile 限定符和引用修飾符不能忽略)。
  • 如果初始化表達(dá)式是一個(gè)右值表達(dá)式(如字面值、臨時(shí)對象、表達(dá)式的結(jié)果等),那么decltype(auto)推導(dǎo)為對應(yīng)右值的類型(const/volatile 限定符和引用修飾符不能忽略)。
  • 如果初始化表達(dá)式是一個(gè)將亡值(如移動賦值),那么decltype(auto)推導(dǎo)為對應(yīng)類型的右值引用

示例 1:標(biāo)識符表達(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)作為一種返回類型的語法。它用于在函數(shù)聲明中指定返回類型,該返回類型將從函數(shù)體中的表達(dá)式推導(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;      // 編譯錯(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;

對比上述三種函數(shù)返回值類型推導(dǎo),decltype(auto)可讓編譯器根據(jù)表達(dá)式的類型自動推導(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,而自定義類型,浮點(diǎn)數(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個(gè)常見問題入手,循序漸進(jìn)的分析了從C++11開始引入的關(guān)鍵字decltype,希望本文可以對大家有所幫助。

相關(guān)文章

  • Dev-C++無法使用bits/stdc++.h問題及解決

    Dev-C++無法使用bits/stdc++.h問題及解決

    這篇文章主要介紹了Dev-C++無法使用bits/stdc++.h問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • C語言實(shí)現(xiàn)最簡單的剪刀石頭布小游戲示例

    C語言實(shí)現(xiàn)最簡單的剪刀石頭布小游戲示例

    這篇文章主要介紹了C語言實(shí)現(xiàn)最簡單的剪刀石頭布小游戲,涉及C語言數(shù)組、隨機(jī)數(shù)與數(shù)值運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下
    2017-09-09
  • 剖析C++中的常量表達(dá)式與省略號的相關(guān)作用

    剖析C++中的常量表達(dá)式與省略號的相關(guān)作用

    這篇文章主要介紹了C++中的常量表達(dá)式與省略號的相關(guān)作用,以及表達(dá)式中的可變參數(shù)模板示例,需要的朋友可以參考下
    2016-01-01
  • C++實(shí)現(xiàn)隨機(jī)生成迷宮地牢

    C++實(shí)現(xiàn)隨機(jī)生成迷宮地牢

    這篇文章主要介紹了C++實(shí)現(xiàn)隨機(jī)生成迷宮地牢的相關(guān)資料及代碼分享,推薦給大家,有需要的小伙伴可以參考下。
    2015-03-03
  • C++數(shù)據(jù)結(jié)構(gòu)與算法之判斷一個(gè)鏈表是否為回文結(jié)構(gòu)的方法

    C++數(shù)據(jù)結(jié)構(gòu)與算法之判斷一個(gè)鏈表是否為回文結(jié)構(gòu)的方法

    這篇文章主要介紹了C++數(shù)據(jù)結(jié)構(gòu)與算法之判斷一個(gè)鏈表是否為回文結(jié)構(gòu)的方法,結(jié)合實(shí)例形式分析了回文結(jié)構(gòu)并結(jié)合實(shí)例給出了C++判斷回文的操作技巧,需要的朋友可以參考下
    2017-05-05
  • 如何利用C語言輸出3D立體感心形圖詳解

    如何利用C語言輸出3D立體感心形圖詳解

    其實(shí)我們在程序中也有很多樂趣的,只是很多人不善于發(fā)現(xiàn),這篇文章主要給大家介紹了關(guān)于C語言輸出3D立體感心形圖的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-12-12
  • 深入解析C++11?lambda表達(dá)式/包裝器/線程庫

    深入解析C++11?lambda表達(dá)式/包裝器/線程庫

    這篇文章主要介紹了C++11?lambda表達(dá)式/包裝器/線程庫的相關(guān)知識,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • C++實(shí)現(xiàn)LeetCode(133.克隆無向圖)

    C++實(shí)現(xiàn)LeetCode(133.克隆無向圖)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(133.克隆無向圖),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • c語言:基于函數(shù)指針的兩個(gè)示例分析

    c語言:基于函數(shù)指針的兩個(gè)示例分析

    本篇文章是對c語言中函數(shù)指針的兩個(gè)示例做了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++ decltype用法舉例說明

    C++ decltype用法舉例說明

    decltype是C++11添加的一個(gè)新的關(guān)鍵字,目的是選擇并返回操作數(shù)的數(shù)據(jù)類型,重要的是,在此過程中編譯器分析表達(dá)式并得到它的類型,卻不實(shí)際計(jì)算表達(dá)式的值,今天通過本文給大家介紹C++ decltype用法,通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2021-07-07

最新評論