2014:C++14 泛型 Lambda——三年一版節奏的開始#
事件#
2014 年 12 月,C++14(ISO/IEC 14882:2014)發佈。這是第一個遵循「三年一版」節奏的標準——以小步快跑取代 C++11 的大爆發。
關鍵語法/特性#
- 泛型 Lambda:
[](auto x, auto y) { return x + y; }——參數可用auto,Lambda 參數型別由呼叫處推導。 - 函式回傳型別推論:
auto f() { return 42; }。 - 放寬的 constexpr:可含區域變數、迴圈、分支——幾乎是完整的編譯期程式語言。
- 變數樣板:
template<class T> constexpr T pi = T(3.14...); std::make_unique:補上 C++11 遺漏的一角(make_shared有、make_unique卻沒有)。- 二進位字面值
0b1010、數字分隔符1'000'000、[[deprecated]]屬性。
為何重要#
- 泛型 Lambda 讓「以行為為參數」的風格完整:C++11 的 Lambda 只能寫死參數型別,C++14 之後才能寫出真正泛型的組合式程式碼——與 STL 演算法、ranges(C++20 的前身)無縫銜接。
- 放寬 constexpr:編譯期計算從「只能寫一行遞迴」進化成「能寫迴圈的完整程式」——
constexpr函式庫(如編譯期字串處理)就此萌芽。 - 三年一版節奏:確立了 C++ 不再讓標準與實務脫節 13 年的承諾。
理論與實用原因#
- 理論原因:泛型 Lambda 即「隱式參數化多型」(implicit polymorphism)——語法糖背後是樣板展開;放寬 constexpr 源自「常數求值器即直譯器」的編譯器理論。
- 實用原因:C++11 來不及完成的細節(make_unique、泛型 Lambda、放寬 constexpr)在三年內補齊,讓「現代 C++」風格可以完全落地。
彌補了什麼缺陷#
彌補了 C++11「Lambda 參數型別必须寫死、constexpr 太受限、make_unique 缺漏」的缺陷——這是「現代 C++」的第二塊拼圖。
程式範例#
泛型 Lambda:參數型別不再寫死
#include <string>
#include <vector>
// C++11 舊寫法:Lambda 參數型別必須寫死,想支援多型別要寫好幾份
auto add_int = [](int a, int b) { return a + b; };
auto add_double = [](double a, double b) { return a + b; };
// C++14:參數用 auto,一次支援所有可用 + 的型別(背後是樣板展開)
auto add = [](auto a, auto b) { return a + b; };
int i = add(1, 2); // int 版本
double d = add(1.5, 2.5); // double 版本
std::string s = add(std::string("a"), std::string("b")); // 字串串接
函式回傳型別推論
// C++11:回傳型別要用尾置宣告,冗長
auto add11(int a, int b) -> int { return a + b; }
// C++14:回傳型別直接推論
auto add14(int a, int b) { return a + b; } // 推論為 int
template <class T>
auto pick(bool flag, T a, T b) { return flag ? a : b; } // 推論為 T
放寬 constexpr:編譯期可以寫迴圈
// C++11 舊寫法:constexpr 函式只能一行遞迴
constexpr int fact11(int n) {
return n <= 1 ? 1 : n * fact11(n - 1);
}
// C++14:constexpr 可含區域變數與迴圈,幾乎是完整編譯期語言
constexpr int fact14(int n) {
int result = 1;
for (int i = 2; i <= n; ++i) result *= i;
return result;
}
constexpr int x = fact14(5); // 編譯期算出 120,可當陣列大小
int arr[x];
std::make_unique:補上 C++11 的缺漏
#include <memory>
void f() {
// C++11 舊寫法:new 與 unique_ptr 分開寫,例外安全性較差
std::unique_ptr<int> p1(new int(42));
// C++14:make_unique 終於進標準庫——與 make_shared 對稱
auto p2 = std::make_unique<int>(42);
}