在 C++14 中新增泛型lambda时,是使用基于 auto 的语法,比较简单但也带来一定的局限性,因此在 C++20 中进行改进,新增模板语法的泛型 lambda 。让我们先回顾一下基于 auto 语法的泛型 lambda ,以及其局限性,然后再看 C++20 新增的基于模板的泛型 lambda 。
(C++14)基于 auto 的泛型 lambda
C++14 中的泛型 lambda ,是使用 lambda 参数中的 auto 关键字来表示不同的类型,一个例子如下:
#include #include using std::cout, std::endl, std::string;int main( int argc, char * argv[] ){ auto f1 = [] ( auto x, auto y ) { return x + y; }; cout << &f1 << endl; string (*fp1)( string, string ) = f1; double (*fp2)( double, int ) = f1; cout << (void *)fp1 << " " << (void *)fp2 << endl; double a1 = f1( 2, 5.0 ); string a2 = fp1( "2", "5.0" ); cout << a1 << " " << a2 << endl; return 0;}
上述代码编译和执行的结果为:
[smlc@test code]$ g++ -std=c++20 a12.cpp[smlc@test code]$ ./a.out0x7ffcef96de2f0x401f18 0x401f4b7 25.0
由于 lambda 表达式实际定义的是一个闭包类(ClosureType),通过重载 operator () 来提供仿函数的调用。通过 auto 关键字定义的泛型 lambda ,相当于如下的定义:
struct { template auto operator() ( T x, U y ) const { return x + y; }};
基于 auto 的泛型 lambda 的局限性
基于 auto 的泛型 lambda ,最主要的局限性,是 auto 描述是整个类型,而不能像模板一样细化类型的模式。例如如果想 lambda 的参数类型是某种类型的数组(std::vector),当前基于 auto 的泛型 lambda 无法表示,只能将参数定义成所有类型,然后再通过其他手段限制只能是数组类型(std::vector),同时,如果想获取数组里面的具体类型,也需要使用其他手段来获取。
template struct is_std_vector : std::false_type { };template struct is_std_vector<:vector>> : std::true_type { };auto f = [ ] ( auto vecType ) { static_assert( is_std_vector< decltype( vecType ) >::value, "" ); // <1> 额外的判断std::vector using T = typename decltype( vecType )::value_type; // <2> 使用其他手段获取数组的具体类型 // ... other code ... };
其他还有很多类似的需要细化类型的情况,例如多个参数之间的类型有关联,或者是要去掉类型 const 等附加信息,这些都需要通过 decltype 来获取类型然后再进行各种处理,反而使代码更复杂了,因此增加模板语法的 lambda 是有必要的。
(C++20)新增基于模板的 lambda 语法
C++20中新增了基于模板的lambda语法,对于上面的情况可以更简洁的描述,和其他模板的语法也保持一致:
auto f = [ ] < typename T > ( std::vector vecType ) { // <1> 无需额外判断std::vector,具体数组类型也可以直接使用T // ... other code ... }
语法上比较简单,不需要额外的 template 关键字,直接在 “ [ ] ” 和 “ ( ... ) ” 之间增加 “ < ... > ” 表示模板参数,然后在 lambda 参数和函数体中,就可以使用模板参数中描述的类型了。
基于模板的lambda也可以同时使用auto类型的参数,但不建议这样使用,混合使用这两种方式并不能带来额外的好处,反而使代码更加难懂。既然已经使用了模板,那么auto类型的参数也改为模板参数类型好了。
【往期回顾】
C++20 新特性(11):lambda对this的捕捉改进
C++20 新特性(10):字符串类型的改进