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

C++11之后的decltype類型指示符詳解

 更新時間:2023年01月10日 10:51:08   作者:smart_cat  
為了滿足這一要求,C++11?新標準引入了另一種類型說明符?decltype?,它的作用是選擇并返回操作數(shù)的數(shù)據(jù)類型,這篇文章主要介紹了C++11之后的decltype類型指示符,需要的朋友可以參考下

一、什么是decltype類型指示符

有時會遇到這種情況:希望從表達式的類型推斷出要定義的變量的類型,但是不想用該表達式的值初始化變量。為了滿足這一要求,C++11 新標準引入了另一種類型說明符 decltype ,它的作用是選擇并返回操作數(shù)的數(shù)據(jù)類型。在此過程中,編譯器分析表達式并得到它的類型,卻并不實際計算表達式的值。

decltype(f()) sum = x;  // sum 的類型就是函數(shù)f的返回類型

編譯器并不實際調(diào)用函數(shù)f,而是使用當調(diào)用發(fā)生時f的返回值類型作為sum的類型。換句話說,編譯器為sum指定的類型是什么呢?就是假如f被調(diào)用的話將會返回的那個類型。

二、typeid運算符

C++標準提供了一個typeid運算符來獲取與目標操作數(shù)類型有關(guān)的信息。獲取的類型信息會包含在一個類型為std::type_info的對象里。我們可以調(diào)用成員函數(shù)name獲取其類型名,例如:

#include <iostream>

using namespace std;

template<class T1, class T2>
auto sum(T1 t1, T2 t2) -> decltype(t1 + t2)
{
    return t1 + t2;
}

int main()
{
    auto s1 = sum(2, 3);
    cout << "sum(2, 3)=" << s1 << endl;
    cout << "s1 type: " << typeid(s1).name() << endl;

    auto s2 = sum(2.0, 3.0);
    cout << "sum(2.0, 3.0)=" << s2 << endl;
    cout << "s2 type: " << typeid(s2).name() << endl;

    return 0;
}

20230109221937

值得注意的是,成員函數(shù)name返回的類型名在C++標準中并沒有明確的規(guī)范,所以輸出的類型名會因編譯器而異。比如,MSVC會輸出一個符合程序員閱讀習慣的名稱,而GCC則會輸出一個它自定義的名稱。

另外,還有3點也需要注意。

  1. typeid的返回值是一個左值,且其生命周期一直被擴展到程序生命周期結(jié)束。
  2. typeid返回的std::type_info刪除了復(fù)制構(gòu)造函數(shù),若想

保存std::type_info,只能獲取其引用或者指針,例如:

auto t1 = typeid(int); // 編譯失敗,沒有復(fù)制構(gòu)造函數(shù)無法編譯
auto &t2 = typeid(int); // 編譯成功,t2推導(dǎo)為const std::type_info&
auto t3 = &typeid(int); // 編譯成功,t3推導(dǎo)為const std::type_info*

3.typeid的返回值總是忽略類型的 cv 限定符,也就是

typeid(const T)== typeid(T))

gcc的擴展中還提供了一個名為typeof的運算符,它可以在編譯期就獲取操作數(shù)的具體類型,但typeof并不是C++ 標準。typeid可以獲取類型信息并幫助我們判斷類型之間的關(guān)系,但遺憾的是,它并不能像typeof那樣在編譯期就確定對象類型。

三、使用decltype指示符

常規(guī)用法如下:

int x1 = 0;
decltype(x1) x2 = 0;
std::cout << typeid(x2).name() << std::endl; // x2的類型為int

double x3 = 0;
decltype(x1 + x3) x4 = x1 + x3;
std::cout << typeid(x4).name() << std::endl; // x1+x3的類型為double

decltype({1, 2}) x5; // 編譯失敗,{1, 2}不是表達式

形參列表中也可以使用:

int x1 = 0;
decltype(x1) sum(decltype(x1) a1, decltype(a1) a2)
{
    return a1 + a2;
}
auto x2 = sum(5, 10);

decltype在尾置返回類型時有著很大用處,例如:

template<class T1, class T2>
auto sum(T1 t1, T2 t2) -> decltype(t1 + t2)
{
    return t1 + t2;
}

需要說明的是,上述用法只推薦在C++11標準的編譯環(huán)境中使用,因為C++14標準已經(jīng)支持對auto聲明的返回類型進行推導(dǎo)了,所以以上代碼可以簡化為:

#include <iostream>

using namespace std;

template<class T1, class T2>
auto sum(T1 t1, T2 t2)
{
    return t1 + t2;
}

int main()
{
    auto res = sum(1, 2.0);
    cout << "res=" << res << endl;
    cout << "res type: " << typeid(res).name() << endl;

    return 0;
}

20230109230235

那既然在C++14 標準中decltype的作用又被auto代替了,是否從C++14標準以后decltype就沒有用武之地了呢?并不是這樣的,auto作為返回類型的占位符還存在一些問題,請看下面的例子:

template<class T>
auto return_ref(T& t)
{
    return t;
}

int x = 0;
cout << "x is reference value: " << std::is_reference_v<decltype(return_ref(x))> << endl;

在上面的代碼中,我們期望return_ref返回的是一個T的引用類型,但是如果編譯此段代碼,會發(fā)現(xiàn)auto被推導(dǎo)為值類型。如果想正確地返回引用類型,則需要用到decltype說明符,例如:

template<class T>
auto return_ref(T& t) -> decltype(t)
{
    return t;
}

以上兩段代碼幾乎相同,只是在return_ref函數(shù)的尾部用decltype(t)聲明了返回類型。

當然了,還有一種方法也可以,使用 auto& :

template<class T>
auto& return_ref1(T& t)
{
    return t;
}

四、decltype和引用

如果 decltype 使用的表達式不是一個變量,則 decltype 返回表達式結(jié)果對應(yīng)的類型。有些表達式將向 decltype 返回一個引用類型。一般當這種情況發(fā)生時,意味著該表達式的結(jié)果對象能作為一條賦值語句的左值:

int i = 42, *p = &i, &r = i;
decltype(r + 0) b;  // 正確,加法的結(jié)果是int,因此b是一個(未初始化的)int
decltype(*p) c;     // 錯誤,c是int&, 必須初始化

如果表達式的內(nèi)容是解引用操作,則decltype將得到引用類型,所以decltype(*p)的結(jié)果類型是int&,而非int。

decltype 和 auto 的重要區(qū)別是,decltype 的結(jié)果類型與表達式形式密切相關(guān)。有一種情況需要特別注意:對于 decltype 來說,如果變量名加上了一對括號,則得到的類型與不加括號時會有所不同。不加括號的話,得到的結(jié)果就是該變量的類型。如果給變量加上了一層或多層括號,編譯器就會把它當成是一個表達式。變量是一種可以作為賦值語句左值的特殊表達式,所以這樣的decltype就會得到引用類型:

decltype((i)) d;    // 錯誤,d是int&,必須初始化
decltype(i) e;      // 正確,e是一個未初始化的int

總結(jié)就是:

  • decltype((val)) 的結(jié)果永遠是引用。
  • decltype(val) 的結(jié)果,只有當val本身就是一個引用時,才是引用

五、decltype(auto)

在 C++14 標準中出現(xiàn)了 decltype 和 auto 兩個關(guān)鍵字的結(jié)合體:decltype(auto)。它的作用簡單來說,就是告訴編譯器用decltype的推導(dǎo)表達式規(guī)則來推導(dǎo)auto。另外需要注意的是,decltype(auto)必須單獨聲明,也就是它不能結(jié)合指針、引用以及cv限定符。

int i;
int&& f();
auto x1a = i; // x1a推導(dǎo)類型為int
decltype(auto) x1d = i; // x1d推導(dǎo)類型為int
auto x2a = (i); // x2a推導(dǎo)類型為int
decltype(auto) x2d = (i); // x2d推導(dǎo)類型為int&
auto x3a = f(); // x3a推導(dǎo)類型為int
decltype(auto) x3d = f(); // x3d推導(dǎo)類型為int&&
auto x4a = { 1, 2 }; // x4a推導(dǎo)類型為
std::initializer_list<int>
decltype(auto) x4d = { 1, 2 }; // 編譯失敗, {1, 2}不是表達式
auto *x5a = &i; // x5a推導(dǎo)類型為int*
decltype(auto)*x5d = &i; // 編譯失敗,decltype(auto)必須單獨聲明

有了decltype(auto)之后,我們又多了一種返回引用的形式:

template<class T>
decltype(auto) return_ref(T& t)
{
    return t;
}

在C++17 標準中,decltype(auto)還能作為非類型模板形參的占位符,例如:

#include <iostream>
template<decltype(auto) N>
void f()
{
    std::cout << N << std::endl;
}

六、本章代碼匯總

#include <iostream>

using namespace std;

template<class T1, class T2>
auto sum(T1 t1, T2 t2)
{
    return t1 + t2;
}

template<class T>
auto return_ref(T& t)
{
    return t;
}

template<class T>
auto& return_ref1(T& t)
{
    return t;
}

template<class T>
auto return_ref2(T& t) -> decltype(t)
{
    return t;
}

template<class T>
decltype(auto) return_ref3(T& t)
{
    return t;
}

template<decltype(auto) N>
void f()
{
    cout << N << endl;
}

int main()
{
    auto res = sum(1, 2.0);
    cout << "res=" << res << endl;
    cout << "res type: " << typeid(res).name() << endl;

    int x = 0;
    cout << "x is reference value: " << std::is_reference_v<decltype(return_ref(x))> << endl;
    cout << "x is reference value: " << std::is_reference_v<decltype(return_ref1(x))> << endl;
    cout << "x is reference value: " << std::is_reference_v<decltype(return_ref2(x))> << endl;
    cout << "x is reference value: " << std::is_reference_v<decltype(return_ref3(x))> << endl;

    return 0;
}

20230109235259

到此這篇關(guān)于C++11之后的decltype類型指示符的文章就介紹到這了,更多相關(guān)C++11 decltype類型指示符內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • c++11 符號修飾與函數(shù)簽名、函數(shù)指針、匿名函數(shù)、仿函數(shù)、std::function與std::bind

    c++11 符號修飾與函數(shù)簽名、函數(shù)指針、匿名函數(shù)、仿函數(shù)、std::function與std::bind

    這篇文章主要介紹了c++11 符號修飾與函數(shù)簽名、函數(shù)指針、匿名函數(shù)、仿函數(shù)、std::function與std::bind,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • opencv實現(xiàn)圖像顏色空間轉(zhuǎn)換

    opencv實現(xiàn)圖像顏色空間轉(zhuǎn)換

    這篇文章主要為大家詳細介紹了opencv實現(xiàn)圖像顏色空間轉(zhuǎn)換,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • vc中使用SendMessage自定義消息函數(shù)

    vc中使用SendMessage自定義消息函數(shù)

    這篇文章主要介紹了vc中使用SendMessage自定義消息函數(shù)的相關(guān)資料,需要的朋友可以參考下
    2015-06-06
  • 一篇文章徹底搞懂C++常見容器

    一篇文章徹底搞懂C++常見容器

    容器就是一些特定類型對象的集合,容器可以分為順序容器和關(guān)聯(lián)容器,下面這篇文章主要給大家介紹了關(guān)于C++常見容器的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-02-02
  • C++中的Z字形變換問題

    C++中的Z字形變換問題

    將一個給定字符串?s?根據(jù)給定的行數(shù)?numRows?,以從上往下、從左到右進行?Z?字形排列,這樣一個需求怎么實現(xiàn)呢,下面小編給大家?guī)砹薈++中的Z字形變換問題,需要的朋友可以參考下
    2022-07-07
  • C++實現(xiàn)走迷宮小游戲

    C++實現(xiàn)走迷宮小游戲

    這篇文章主要為大家詳細介紹了C++實現(xiàn)走迷宮小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • c++深入淺出講解堆排序和堆

    c++深入淺出講解堆排序和堆

    在c++里有很多排序方法,比如相對簡單的冒泡排序、選擇排序、插入排序,還有 STL里的sort函數(shù)  手寫快排  歸并排序等,還有就是堆排序,這次主要說堆排序和堆
    2022-03-03
  • C++庫std::flush的具體使用

    C++庫std::flush的具體使用

    std::flush是C++標準庫中的一個操作符,用于刷新輸出流,本文主要介紹了C++庫std::flush的具體使用,具有一定的參考價值,感興趣的可以了解一下
    2024-02-02
  • opencv學(xué)習筆記C++繪制灰度直方圖

    opencv學(xué)習筆記C++繪制灰度直方圖

    這篇文章主要為大家介紹了opencv學(xué)習筆記C++繪制灰度直方圖的實現(xiàn)代碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • C語言實現(xiàn)通用數(shù)據(jù)結(jié)構(gòu)之通用集合(HashSet)

    C語言實現(xiàn)通用數(shù)據(jù)結(jié)構(gòu)之通用集合(HashSet)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)通用數(shù)據(jù)結(jié)構(gòu)之通用集合,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11

最新評論