14-2(C++11)類型推導、類型計算
- 類型推導
- auto關鍵字
- auto類型推斷本質
- auto與引用 聯用
- auto關鍵字的使用限制
- 類型計算
- 類型計算分類
- 與類型推導相比
- 四種類型計算的規則
- 返回值后置
類型推導
auto關鍵字
- C++98中,auto表示棧變量,通常省略不寫
- C++11中,給auto賦予新的語義,表示自動類型推導
- 既根據對變量進行初始化時所使用的數據的類型,由編譯器自動推導出所定義變量的實際類型
- 既根據對變量進行初始化時所使用的數據的類型,由編譯器自動推導出所定義變量的實際類型
auto類型推斷本質
- 按照定義獨立對象并根據初始化數據的類型進行推導
- 無法自動推斷 const,只能在auto的上下文顯示指明
- 如果給出的 初始化數據類型為常量指針,則可以自動推導const
// 類型推導不是類型照抄
#include <iostream>
#include <typeinfo>
using namespace std;int main( void ){int a = 10;const int b = 10;auto c = a;// auto: int c: intcout << "c的類型:" << typeid(c).name() << endl; // icout << "&c: " << &c << ", &a: " << &a << endl; // 地址不同c++; // 允許更改auto d = b;// auto: int d: intcout << "d的類型:" << typeid(d).name() << endl; // icout << "&d: " << &d << ", &b: " << &b << endl; // 地址不同d++; // 允許更改const auto e = b;// auto: int e: const intcout << "e的類型:" << typeid(e).name() << endl; // icout << "&e: " << &e << ", &b: " << &b << endl; // 地址不同
// e++; // 不允許更改auto f = &b; // 如果初始化數據的類型是常量指針,則可以自動推導const(第一種可以自動推導const的情況)// auto: const int* f: const int*cout << "f的類型:" << typeid(f).name() << endl; // PKi
// *f = 666;f = NULL;return 0;
}
auto與引用 聯用
- 按照定義獨立對象并根據初始化數據的類型進行推導,所以不可能推導出引用
- 除非auto的上下文指明按照引用推導
- 若指明按引用推導并且目標帶有常屬性,則可以自動推導const
// 類型推導和引用聯用
#include <iostream>
#include <typeinfo>
using namespace std;int main( void ){int a = 10;const int b = 10;auto c = a;// auto: int c: intcout << "c的類型:" << typeid(c).name() << endl; // icout << "&c: " << &c << ", &a: " << &a << endl; // 地址不同c++; // 允許更改auto& d = a;// auto: int d: int&cout << "d的類型:" << typeid(d).name() << endl; // icout << "&d: " << &d << ", &a: " << &a << endl; // 地址相同d++; // 允許更改auto& e = b; // 如果指明按引用推導,并且目標帶有常屬性,則也可以自動推導出const(這是第二種自動推導出const的情況)// auto: const int e: const int&cout << "e的類型:" << typeid(e).name() << endl; // icout << "&e: " << &e << ", &b: " << &b << endl; // 地址相同
// e++; // 不允許更改return 0;
}
auto關鍵字的使用限制
- 函數形參類型無法推導(C++14標準支持)
- 類的成員變量無法推導
// 類型推導的局限性
#include <iostream>
#include <typeinfo>
using namespace std;
/*
void foo(auto v){// ...
}
*/
/*
class A{
public:auto a; // 聲明auto b; // 聲明
};
*/int main( void ){
// foo(10);
// foo(3.14);return 0;
}
類型計算
類型計算分類
- C語言: sizeof - 計算類型的大小
- C++語言: typeid - 可以獲取類型的信息字符串
- C++11: decltype - 獲取參數表達式的類型
注意事項:類型計算由編譯器確定,并不是運行期確定
與類型推導相比
- 對類型的確定更加精準
const int a = 10;
auto b = a; // b類型推導為int
decltype(a) c = a; //c類型計算為 const int
- 可以做到類型相同但值不同
const int a = 10:
auto b=a;
decltype(a) c = 100;
// 類型推導和類型計算的比較
#include <iostream>
#include <typeinfo>
using namespace std;int main( void ){const int a = 10;auto b = a;// auto : int b : intcout << "b的類型:" << typeid(b).name() << endl; // icout << "&b: " << &b << ", &a:" << &a << endl; // 地址不同b++; // 允許更改// 類型計算比類型推導在類型的確定上會更加精準decltype(a) c = 666;// = a;// c: const intcout << "c的類型:" << typeid(c).name() << endl; // i cout << "&c: " << &c << ", &a:" << &a << endl; // 地址不同
// c++; // 不允許更改return 0;
}
四種類型計算的規則
- 標識符表達式,直接取表達式的類型
- 函數表達式,取函數返回值的類型
- 其他表達式
- 如果表達式的值為左值,則取左值引用的類型
- 如果表達式的值為右值,則取該右值本身的類型
// 四種類型計算的規則
#include <iostream>
#include <typeinfo>
using namespace std;double foo();int main( void ){int a = 10;// 如果給decltype傳遞的是標識符表達式,則編譯器根據標識符的類型,作為最終計算出的類型decltype(a) c = a;// c: intcout << "c的類型:" << typeid(c).name() << endl; // icout << "&c:" << &c << ", &a:" << &a << endl; // 地址不同c++; // 允許更改// 如果給decltype傳遞的是函數表達式,則編譯器根據函數的返回值的類型,作為最終計算出的類型decltype(foo()) d = a;// d: doublecout << "d的類型:" << typeid(d).name() << endl; // dcout << "&d:" << &d << ", &a:" << &a << endl; // 地址不同d++; // 允許更改// 如果是其它表達式,并且表達式結果為左值,則編譯器取該左值引用的類型,作為最終計算出的類型decltype(++a) e = a;// e: int&cout << "e的類型:" << typeid(e).name() << endl; // icout << "&e:" << &e << ", &a:" << &a << endl; // 地址相同e++; // 允許更改// 如果是其它表達式,并且表達式結果為右值,則編譯器取該右值本身的類型,做為最終計算出的類型decltype(a++) f = a;// f: intcout << "f的類型:" << typeid(f).name() << endl; // icout << "&f:" << &f << ", &a:" << &a << endl; // 地址不同f++; // 允許更改 return 0;
}
返回值后置
auto 函數名 (形參表) ->decltype(表達式)
#include <iostream>
#include <typeinfo>
using namespace std;auto foo(int x, double y) -> decltype(x+y){return x + y;
}int main( void ){auto f = foo(3,3.14);cout << "f的類型:" << typeid(f).name() << endl;return 0;
}