基本用法與區別
auto 總是推導出“值類型”,絕不會是“引用”,如果有引用,auto會把引用去掉,推導出值類型; auto 可以附加上 const、volatile、*、& 這樣的類型修飾符,得到新的類型。
auto x = 10L; // auto推導為long,x是long
auto& x1 = x; // auto推導為long,x1是long&
auto* x2 = &x; // auto推導為long,x2是long*
const auto& x3 = x; // auto推導為long,x3是const long&
auto x4 = &x3; // auto推導為const long*,x4是const long*
auto 只能用于“初始化 “, “自動類型推導”要求必須從表達式推導,那在沒有表達式的時候
就需要使用decltype + 表達式,自己解決類型推導問題。
decltype 的形式很像函數,后面的圓括號里就是可用于計算類型的表達式(和 sizeof 有點 類似),其他方面就和 auto 一樣了,也能加上 const、*、& 來修飾 ,它是用來直接聲明變量的。
int x = 0; // 整型變量
decltype(x) x1; // 推導為int,x1是int
decltype(x)& x2 = x; // 推導為int,x2是int&,引用必須賦值
decltype(x)* x3; // 推導為int,x3是int*
decltype(&x) x4; // 推導為int*,x4是int*
decltype(&x)* x5; // 推導為int*,x5是int**
decltype(x2) x6 = x2; // 推導為int&,x6是int&,引用必須賦值
decltype 不僅能夠推導出值類型,還能夠推導出引用類型,也就是表達式的“原始類 型”。
delctype的缺點是 是寫起來略麻煩,特別在用于初始化的時候,表達式要重復兩次 (左邊的類型計算,右邊的初始化)
當decltype(auto)被用于聲明變量時,該變量必須立即初始化。假設該變量的初始化表達式為e,那么該變量的類型將被推導為decltype(e)。也就是說在推導變量類型時,先用初始化表達式替換decltype(auto)當中的auto,然后再根據decltype的語法規則來確定變量的類型。
int x = 0; // 整型變量
decltype(auto) x2 = &x; // 推導為int*
decltype(auto) x3 = x1; // 推導為int&
常見用法
auto的 range-based for 用法
不需要關心容器元素類型、迭 代器返回值和首末位置,就能非常輕松地完成遍歷操作
vector<int> v = {2,3,5,7,11}; // vector順序容器
for(const auto& i : v) { // 常引用方式訪問元素,避免拷貝代價cout << i << ","; // 常引用不會改變元素的值
}
for(auto& i : v) { // 引用方式訪問元素i++; // 可以改變元素的值cout << i << ",";
}
decltype 簡化函數指針
// UNIX信號函數的原型,看著就讓人暈
void (*signal(int signo, void (*func)(int)))(int)
// 使用decltype可以輕松得到函數指針類型
using sig_func_ptr_t = decltype(&signal) ;
decltype在類內部實現參數推導
在定義類的時候,auto 被禁用了。可以用decltype獲取表達式類型,配合using生成別名
class DemoClass final {
public:using set_type = std::set<int>; // 集合類型別名
private:set_type m_set; // 使用別名定義成員變量// 使用decltype計算表達式的類型,定義別名using iter_type = decltype(m_set.begin());iter_type m_pos; // 類型別名定義成員變量
};