decltype 和 auto
返回類型推導 decltype
?
decltype 推導規則
編譯器將根據以下三條規則得出結果:
- 如果 exp 是一個不被括號( )包圍的表達式,或者是一個類成員訪問表達式,或者是一個單獨的變量,那么 decltype(exp) 的類型就和 exp 一致,這是最普遍最常見的情況。
- 如果 exp 是函數調用,那么 decltype(exp) 的類型就和函數返回值的類型一致。
- 如果 exp 是一個左值,或者被括號( )包圍,那么 decltype(exp) 的類型就是 exp 的引用;假設 exp 的類型為 T,那么 decltype(exp) 的類型就是 T&。
用法
在難以或不可能以標準寫法進行聲明的類型時,decltype 很有用,例如 lambda 相關類型或依賴于模板形參的類型。C++11新標準引入了decltype類型說明符,它的作用是選擇并返回操作數的數據類型,在此過程中,編譯器分析表達式并得到它的類型,卻不實際計算表達式的值。
據我自己的理解,這個關鍵字經常被用在模板編程中,模板在使用時,可能會出現不知道應該聲明是什么類型的狀況
template<typename?T1,typename?T2>?type? fun(T1 a,T2 b){ ?type? aplusb=a+b;????return?aplusb;}在上述情況中,我們事先并不知道aplusb的類型,無法對其進行聲明。
 但是C++11中新增加的關鍵字decltype解決了這個問題
為什么函數的返回值是auto嘞?由于在提供返回類型之前,還未聲明變量a,b所以無法對返回類型設置為decltype(a,b)
 這時候在C++11中提供了一個解決方案,就是后置返回類型。簡單的說就是把返回值后置。
例子
#include?<iostream>struct A { double x; };const?A*?a;decltype(a->x) y; // y 的類型是 double(其聲明類型)decltype((a->x))?z?=?y;?//?z?的類型是?const?double&(左值表達式)???template<typename T, typename U>auto add(T t, U u) -> decltype(t + u) // 返回類型依賴于模板形參{ // C++14 開始可以推導返回類型 return t+u;}int main() { int i = 33;????decltype(i)?j?=?i?*?2; std::cout << "i = " << i << ", "??????????????<<?"j?=?"?<<?j?<<?'\n'; auto f = [](int a, int b) -> int { return a * b;????}; decltype(f) g = f; // lambda 的類型是獨有且無名的 i = f(2, 2);????j?=?g(3,?3); std::cout << "i = " << i << ", " << "j = " << j << '\n';}輸出:
i = 33, j = 66i = 4, j = 9decltype 的實際應用
auto 的語法格式比 decltype 簡單,所以在一般的類型推導中,使用 auto 比使用 decltype 更加方便,本節僅演示只能使用 decltype 的情形。
 我們知道,auto 只能用于類的靜態成員,不能用于類的非靜態成員(普通成員),如果我們想推導非靜態成員的類型,這個時候就必須使用 decltype 了。下面是一個模板的定義:
單獨看 Base 類中 m_it 成員的定義,很難看出會有什么錯誤,但在使用 Base 類的時候,如果傳入一個 const 類型的容器,編譯器馬上就會彈出一大堆錯誤信息。原因就在于,T::iterator并不能包括所有的迭代器類型,當 T 是一個 const 容器時,應當使用 const_iterator。
 要想解決這個問題,在之前的 C++98/03 版本下只能想辦法把 const 類型的容器用模板特化單獨處理,增加了不少工作量,看起來也非常晦澀。但是有了 C++11 的 decltype 關鍵字,就可以直接這樣寫:
看起來是不是很清爽?
 注意,有些低版本的編譯器不支持T().begin()這種寫法,以上代碼我在 VS2019 下測試通過,在 VS2015 下測試失敗。
?
類型推導之 auto
用法?
C++11中,auto不再是一個存儲類型指示符,而是一個自動推導變量的類型。auto并非是一種類型的聲明,而是一個類型聲明時的“占位符”,編譯器在編譯期間會將auto替換為變量實際的類型。
我覺得auto給我們帶來的最大改變有兩方面。
?解放程序員雙手。有了auto這個神器,媽媽再也不用擔心我的鍵盤手了。auto可以代替以前要打的很長很長的變量類型。
還是用在模板推導,下邊的例子如果沒有auto,x*y就沒有辦法填寫類型了。
需要注意的是:
-  auto 變量必須在定義時初始化,這類似于const關鍵字。 
-  如果初始化表達式是引用,則去除引用語義。 
-  如果初始化表達式為const或volatile(或者兩者兼有),則除去const/volatile語義。 
-  如果auto關鍵字帶上&號,則不去除const語意。 
-  初始化表達式為數組時,auto關鍵字推導類型為指針。 
-  若表達式為數組且auto帶上&,則推導類型為數組類型。 
-  函數或者模板參數不能被聲明為auto 
-  時刻要注意auto并不是一個真正的類型。auto僅僅是一個占位符,它并不是一個真正的類型,不能使用一些以類型為操作數的操作符,如sizeof或者typeid。 
例子
#include <iostream>#include?<utility>template<class T, class U>auto?add(T?t,?U?u)?{?return?t?+?u;?}?//?返回類型是?operator+(T,?U)?的類型// 在其所調用的函數返回引用的情況下// 函數調用的完美轉發必須用 decltype(auto)template<class F, class... Args>decltype(auto) PerfectForward(F fun, Args&&... args) { return fun(std::forward<Args>(args)...); }template<auto n> // C++17 auto 形參聲明auto f() -> std::pair<decltype(n), decltype(n)> // auto 不能從花括號初始化器列表推導{ return {n, n};}int main(){ auto a = 1 + 2; // a 的類型是 int auto b = add(1, 1.2); // b 的類型是 double static_assert(std::is_same_v<decltype(a), int>);????static_assert(std::is_same_v<decltype(b),?double>); auto c0 = a; // c0 的類型是 int,保有 a 的副本 decltype(auto) c1 = a; // c1 的類型是 int,保有 a 的副本 decltype(auto) c2 = (a); // c2 的類型是 int&,為 a 的別名 std::cout << "a, before modification through c2 = " << a << '\n'; ++c2;????std::cout?<<?"a,?after?modification?through?c2?=?"?<<?a?<<?'\n';????auto?[v,?w]?=?f<0>();?//?結構化綁定聲明 auto d = {1, 2}; // OK:d 的類型是 std::initializer_list<int> auto n = {5}; // OK:n 的類型是 std::initializer_list<int>// auto e{1, 2}; // C++17 起錯誤,之前為 std::initializer_list<int> auto m{5}; // OK:C++17 起 m 的類型為 int,之前為 initializer_list<int>//? decltype(auto) z =?{ 1, 2 }?//?錯誤:{1, 2}?不是表達式 // auto 常用于無名類型,例如 lambda 表達式的類型 auto lambda = [](int x) { return x + 3; };?//??auto?int?x;?//?于?C++98?合法,C++11?起錯誤// auto x; // 于 C 合法,于 C++ 錯誤}可能的輸出:
a, before modification through c2 = 3a, after modification through c2 = 4區別
auto 和 decltype 關鍵字都可以自動推導出變量的類型,但它們的用法是有區別的:
auto varname = value;
 decltype(exp) varname = value;
其中,varname 表示變量名,value 表示賦給變量的值,exp 表示一個表達式。
auto 根據=右邊的初始值 value 推導出變量的類型,而 decltype 根據 exp 表達式推導出變量的類型,跟=右邊的 value 沒有關系。?
總結
以上是生活随笔為你收集整理的decltype 和 auto的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 分布式事务理论-二阶段提交(Two-ph
- 下一篇: nullptr/nullptr_t
