template void f(paramtype param);
使用下面的函式呼叫:
f(expr);
我們看到模板型別推斷過程涉及到了模板template、函式f以及引數(包括模板引數和函式引數),呼叫f的時候,編譯器會推斷t和paramtype的型別。auto的實現和這三個部分是有著對應關係的。當使用auto宣告乙個變數,auto關鍵字扮演的是模板型別推斷中t的角色,而型別說明符扮演的是paramtype的角色。看下面的例子:
auto x = 27; //型別說明符就是auto自己
const auto cx =x; //型別說明符為const auto
const auto& rx =x;//型別說明符為const auto&
編譯器使用auto對上面的型別進行推斷就如同使用了下面的模板型別推斷:
templatevoid func_for_x(t param); //paramtype即非引用也非指標
func_for_x(27); // 推斷x的型別,t為int ,paramtype 為 int
templatevoid func_for_cx(const t param); //paramtype即非引用也非指標
func_for_cx(x); //用於推斷cx的型別,t為int,paramtype為 const int
templatevoid func_for_rx(const t& param);//paramtype為引用
func_for_rx(x); // 用於推斷rx的型別
上面舉的例子是第一種和第三種情況:
auto x = 27; //case 3 x型別被推斷為int
const auto cx = x; //case 3 cx被推斷為 const int
const auto &rx = x; //case 1 rx被推斷為const int &
舉乙個情況2的例子:
auto&& uref1 = x; //x為左值,uref1被推斷為左值引用
auto&& uref2 = cx; // cx const int 左值,uref2被推斷為const int &
auto&& uref3 = 27; // 27 為 int 右值,uref3被推斷為 int &&
上篇帖子介紹了對於模板中的非引用paramtype,傳入函式或者陣列實參的時候會退化為指標的情況(而使用引用paramtype的時候,陣列實參會被推斷為指向陣列的引用),auto型別推斷也會如此:
const char name = "r. n. briggs";
auto arr1 = name; // arr1 的型別為const char*
auto& arr2 = name; // arr2 的型別為const char (&)[13]
void somefunc(int, double);
auto func1 = somefunc; // func1的 型別為 void (*)(int, double)
auto& func2 = somefunc; // func2的型別為 void (&)(int, double)
上面介紹的都是auto和模板型別推斷使用原理相同的部分,下面說的不一樣的。
c++98中初始化乙個int有兩種方式:
int x1=27;
int x1(27);
在c++11中,支援統一初始化(uniform initialization):
int x3 = ;
int x3;
四種語法形式的結果只有乙個,初始化乙個int值為27。這裡我們將都使用auto進行初始化:
auto x1 = 27;
auto x2(27);
auto x3 = ;
auto x4;
上面的四句話都能編譯通過,但並沒有和原來的四種形式意義完全一致。前面兩個是一樣的,後面兩句話宣告的變數型別是std::initializer_list,其中包含了單個元素,值為27。
auto x1 = 27; //x1為int,值為27
auto x2(27);//同上
auto x3 = ;//x3為 std::initializer_list,值為
auto x4; //同上
這裡就用到了乙個對於auto的特殊型別推斷規則:當用大括號括起來的值對auto變數進行初始化的時候(叫做統一初始化式),變數型別會被推斷為 std::initializer_list。如果不能夠推斷成此型別(比如,大括號中的值不是同一型別),編譯會出錯:
auto x5 = ; // error! 型別不一致,不能將推斷為std::initializer_list
這裡會發生兩種型別推斷,一種是將統一初始化式推斷為std::initializer_list ,而std::initializer_list本身也是乙個型別為t的模板,因此會根據統一初始化式中的實參對t進行模板型別推斷,這是第二種型別推斷。上面的型別推斷會失敗是因為第二種型別推斷會失敗。
對統一初始化式的處理的不一致是auto和模板型別推斷的唯一區別。使用統一初始化式對auto變數初始化會將其推斷為std::initializer_list,但是模板型別推斷不會這麼做:
auto x = ; // x的型別為 std::initializer_listtemplate// 和auto x等同的模板型別推斷
void f(t param);
f(); // 錯誤!這裡不能推斷t的型別。
如果要達到auto的效果,得按照下面的方式來做:
templatevoid f(std::initializer_listinitlist);
f(); // t被推斷為int, initlist 的型別為 std::initializer_list
在c++11中使用auto時,這裡比較容易出錯,你本來想宣告別的變數,最終卻將其宣告成了乙個 std::initializer_list。因此,要謹慎使用統一初始化。
在c++14中,允許將auto作為函式返回值,也可以用其修飾lambda表示式中的引數。但是這些auto使用的都是模板型別推斷,而不是auto型別推斷,因此乙個函式返回值為auto 型別時,返回統一初始化式的值會出錯:
auto createinitlist()
; // 錯誤!不能推斷
}
下面的方式是對的:
std::initializer_listcreateinitlist()
; //
}
最後總結一下: 現代C 之理解auto型別推斷
template void f paramtype param 使用下面的函式呼叫 f expr 我們看到模板型別推斷過程涉及到了模板template 函式f以及引數 包括模板引數和函式引數 呼叫f的時候,編譯器會推斷t和paramtype的型別。auto的實現和這三個部分是有著對應關係的。當使用a...
auto 與decltype 兩種型別推斷
auto型別計算後推斷,decltype不進行計算 auto會忽略掉頂層const,保留下層const decltype全部進行保留 與auto不同,decltype結果型別與表示式形式密切相關 加上括號與不加括號不同。include include using namespace std int ...
C 11 auto型別推斷和decltype
1.auto型別推斷 a.引入原因 程式設計時,經常需要將表示式的值賦給變數,這就要求我們在申明變數的時候,明確知道表示式的型別,然而要做到這一點並不容易,於是引入auto讓編譯器幫我們去做型別分析。b.使用注意事項const int const i 1,const ref const i auto...