C++中的auto,decltype,typedef,using以及typename
auto
值與指標等推導
簡單的東西大家都懂,這裡相當於拾遺
const int a = 10;
auto b = a; // b為 non-const int型別
const const cb = a; // 明確指明const
auto
一般情況下會忽略頂層const
,保留底層const
(頂層const
:指標本身是常量,底層const
int* const apc = &a;
const int* acp = &a;
auto c = apc; // c為 int*型別, 頂層const被忽略
auto c = acp; // c為 const int*型別,底層const被保留
如果像是acpc
這種縫合怪使用auto
推匯出來的是什麼型別大家應該都能猜到吧
返回值推導
C++11中加入了trailing return type(尾返回型別),使用auto
將返回值型別後置
template<typename T1, typename T2> auto MathPlus(T1 a, T2 b) -> decltype(a + b) { return a + b; }
C++14中,auto
的使用更進一步,可以直接推導函式返回值
template<typename T1, typename T2>
auto MathPlus(T1 a, T2 b) { return a + b; }
int main()
{
std::cout << MathPlus(1 + 2.34) << std::endl;
}
std::initializer_list的推導
此功能需要開啟 /std:c++17
C++14中
auto a{ 1, 2, 3 }; //std::initializer_list auto b{ 1 }; //std::initializer_list
C++17中
auto a{ 1, 2, 3 }; //非法
auto b{ 1 }; //int
auto c = { 1, 2, 3 }; //與C++14相同,皆為std::initializer_list
auto d = { 1 }; //與C++14相同,皆為std::initializer_list
Lambda表示式推導
在C++11中,Lambda表示式的引數需要具體的型別宣告
auto MyLambda = [](int a, int b) { return a + b; };
C++14中可以這麼做了
auto MyLambda = [](auto a, auto b){ return a + b; };
這裡再複習以下Lambda表示式的使用,Lambda表示式其實是塊語法糖,其結構如下
[函式物件引數](函式引數列表) mutable throw(型別)->返回值型別 { 函式語句 };
-
當捕獲的是
this
時,它與其所在的成員函式有著相同的protected
,private
訪問許可權,且為按引用傳遞 -
按值捕獲的non-const變數一律無法在Lambda表示式內修改(const就不用說了,在哪都無法修改),
mutable
關鍵字表示可以修改按值捕獲進來的副本(注意修改的是拷貝而不是值本身) -
當明確Lambda表示式不會丟擲異常時,可以使用
noexcept
修飾[]() noexcept { /* 函式語句 */ }
-
當Lambda表示式沒有捕獲任何引數時,它可以轉換成為一個函式指標
通用捕獲
C++14中,可在Capture子句,即[ ]
中引入並初始化新的變數。這些變數不需再存在於Lambda表示式的封閉範圍內。可以使用任意形式的表示式來初始化,同時表示式會自動推匯出變數的型別。捕獲初始化的順序為從左往右執行
auto unip = std::make_unique<int>(10);
auto lambda = [ptr = std::move(unip)]() { /* ptr... */ }
Constexpr Lambda
同樣的,此功能需要開啟std:c++17
顯式constexpr
auto lambda = [](int num) constexpr { return num + 10; };
int arr[lambda(10)];
隱式constexpr
當Lambda滿足constexpr
條件時,會自動隱式宣告其為constexpr
。也就是說上面那個例子其實不加constexpr
也可以
當Lambda轉換成函式指標時,需要顯式指明函式指標為constexpt
constexpr int(Funcp*)(int) = lambda;
int arr[Funcp(100)];
捕獲 *this
全英參考資料Lambda Capture of *this
同樣的,此功能需要開啟std:c++17
在C++14中
class MyClass
{
private:
int num = 10;
int sum(int a, int b) { return a + b; }
public:
auto MyLambda()
{
auto lr = [this]() { num = 100; }; //按引用捕獲
auto lv = [_Myc = *this]() mutable { _Myc.num = 100; }; //按值捕獲
lr();
lv();
}
};
在C++17中,按值捕獲的編寫無需如此複雜
auto lv = [*this]() mutable { num = 100; }; //按值捕獲
重點:[=]
中捕獲進的this
是個指標,因此修改時會改變原來的值
auto MyLambda()
{
int temp = 20;
auto lv = [=]() { num = 100; temp = 200; }; //編譯器報錯,temp無法修改
}
這裡num
可以被修改,且修改的是類中的值本身;temp
不可以被修改,因為沒有mutable
修飾,即使有mutable
,修改的也是捕獲進來的副本,而非值本身
如果不想修改num
,只想修改其副本
auto MyLambda() { auto lv = [=, _Myc = *this] mutable { _Myc.num = 100; }; } //C++14
auto MyLambda() { auto lv = [=, *this] mutable { num = 100; }; } //C++17
若捕獲的是*this
,且想要呼叫成員函式,則需要mutable
修飾。雖然感覺很少會這麼用,但是還是寫一下
auto MyLambda() { auto lv = [_Myc = *this] mutable { int value = _Myc.sum(1,2 ); }; }
auto MyLambda() { auto lv = [*this] mutable { int value = sum(1, 2); }; }
Range-base-loop with auto
參考自知乎-藍色-range-base-loop中使用auto
總結:
- 當你想要拷貝range的元素時,使用
for(auto x : range)
- 當你想要修改range的元素時,使用
for(auto&& x : range)
- 當你想要只讀range的元素時,使用
for(const auto& x : range)
template<auto>
不會,摸了