从C 11起就引入了lambda表达式,C 14又对其进行了丰富,开始支持使用泛型lambda。到现在的C 17 lambda的功能又进行了扩展。在C 17新特性中,主要支持了以下两种场景:
- 在常量表达式中使用
- 需要对当前对象的拷贝时使用,如不同的线程需要创建不同的对象。
1 constexpr lambda表达式
从C 17开始,lambda表达式会尽可能的隐式声明constexpr,在任何只使用有效的编译期上下文的lambda都有可能被用于编译期。这些上下文环境主要包含的场景有:只使用字面变量、没有静态类型、没有虚函数、没有异常捕获及new/delete的上下文环境。如在下面的代码中,因为在lambda中使用了static,表达式将会失去constexpr的能力。
代码语言:javascript复制int main(){
auto squared2 = [](auto val) {
static int calls = 0;
return val*val;
};
std::array<int, squared2(5)> a;
std::cout << squared2(5) << 'n';
return 0;
}
如上代码片段中,第6行代码将lambda中计算的值当做array数组的大小在编译时将会报错。因为在lambda中声明了一个static类型的变量,那么表达式也将失去constepr的能力,既不能在编译器使用。但是它依然可以在运行期使用,试着将第6行代码段进行注释,那么代码可以继续编译且打印出计算结果。
同样的,如果在上面代码中显示定义成constexpr。那么编译时程序将会报错如下:
如此,按照上面上面编译场景,在确认一个lambda表达式是否可用于编译期时就可以在表达式中使用constepr进行判断。如从C 17起,就可以按照以下方式使用:
代码语言:javascript复制int main(){
auto squar = [](auto val) constexpr {
return val*val;
};
return 0;
}
如果要在表达式中指明返回值类型,可以按照如下方式编写代码:
代码语言:javascript复制int main(){
auto squar = [](auto val) constexpr -> int {
return val*val;
};
return 0;
}
在看下面两种lambda表达式中使用constepr的代码段:
代码语言:javascript复制int main()
{
auto squar1 = [](auto val) constexpr {
return val*val;
};
constexpr auto squar2 = [](auto val) {
return val*val;
};
return 0;
}
如上squqr1是在表达式中使用constexpr,squar2则是在变量前使用constexpr,他们表达的含义是不同的,第一种写法是在编译器执行,第二种表示的是在编译器就会对变量进行赋值。如果想同时使用可以按照下面的方式编写代码:
代码语言:javascript复制constexpr auto squar2 = [](auto val) constexpr{
return val*val;
};
2 constexpr lambda的使用
下面的例子主要演示了在lambda中使用constexpr,代码分别在编译期和运行期调用lambda的场景,代码如下:
代码语言:javascript复制auto hash = [](const char* str) {
std::size_t hash = 5381;
while (*str != '