通用 lambdas
Version >= C++ 14
Lambda 函式可以接受任意型別的引數。這允許 lambda 更通用:
auto twice = [](auto x){ return x+x; };
int i = twice(2); // i == 4
std::string s = twice("hello"); // s == "hellohello"
這是通過使閉包型別的 operator()
過載為模板函式在 C++中實現的。以下型別與上述 lambda 閉包具有相同的行為:
struct _unique_lambda_type
{
template<typename T>
auto operator() (T x) const {return x + x;}
};
並非通用 lambda 中的所有引數都必須是通用的:
[](auto x, int y) {return x + y;}
這裡,x
是基於第一個函式引數推匯出來的,而 y
將永遠是 int
。
通用 lambda 也可以通過引用獲取引數,使用 auto
和 &
的通常規則。如果將泛型引數視為 auto&&
,則這是對傳入引數的轉發引用 ,而不是右值引用 :
auto lamb1 = [](int &&x) {return x + 5;};
auto lamb2 = [](auto &&x) {return x + 5;};
int x = 10;
lamb1(x); // Illegal; must use `std::move(x)` for `int&&` parameters.
lamb2(x); // Legal; the type of `x` is deduced as `int&`.
Lambda 函式可以是可變引數並完美地轉發它們的引數:
auto lam = [](auto&&... args){return f(std::forward<decltype(args)>(args)...);};
要麼:
auto lam = [](auto&&... args){return f(decltype(args)(args)...);};
只適用於 auto&&
型別的變數正常工作。
使用泛型 lambda 的一個強有力的理由是訪問語法。
boost::variant<int, double> value;
apply_visitor(value, [&](auto&& e){
std::cout << e;
});
在這裡,我們以多型的方式訪問; 但在其他情況下,我們傳遞的型別的名稱並不有趣:
mutex_wrapped<std::ostream&> os = std::cout;
os.write([&](auto&& os){
os << "hello world\n";
});
重複 std::ostream&
的型別就是這裡的噪音; 每次使用它時都必須提到變數的型別。在這裡,我們建立了一個訪問者,但沒有多型的訪問者; 使用 auto
的原因與你在 for(:)
迴圈中使用 auto
的原因相同。