通用 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 的原因相同。