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