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