[]<typename>(){} 是有效的 lambda 定义吗?

Is []<typename>(){} a valid lambda definition?

本文关键字:有效 lambda 定义 lt typename gt      更新时间:2023-10-16

我正在尝试使用lambdas和编译器,因为这里有另一个关于SO的问题。
我刚刚意识到(这确实很正常)下面的代码是有效的:

int main() {
    auto l = [](){};
    l.operator()();
}

实际上,标准规定闭包类型有一个公共内联函数调用操作符等等,因此能够调用它是有意义的。

我不能通过查看标准(好吧,工作草案)来解释的是,GCC(6.1)编译了以下代码片段(clang 3.9没有):

int main() {
    auto l = []<typename>(){};
    l.operator()<void>();
}

没有警告,没有错误。它是有效的代码还是应该被编译器拒绝?

在N4140 5.1.2 [expr.prim.]lambda], lambda表达式定义为

opt compound-statement

其中"lambda-introducer"[],包含一个可选的"lambda-capture""lambda-declaratoropt"是以开头的东西"(parameter-declaration-clause)"

[]<typename>(){}

不满足这个要求,因为在lambda引入器和lambda声明器之间有一些东西,所以它不是一个有效的lambda表达式。

因此,你的示例代码不是有效的c++,应该被编译器拒绝。


因为它也被标记为gcc,所以我点击了GNU c++扩展列表。我没有找到任何可以使有问题的语法在GNU c++中合法的扩展。

然而,根据该提案(P0428R0)的第4节,该提案建议在c++中添加模板化的lambdas, gcc在2009年获得了上述论文的实验性实现。这可能解释了为什么gcc在这里没有抱怨。

这似乎是一个GCC扩展(模板化的lambdas)。

#include <iostream>
int main() {
    auto l = []<typename T>(T const& x){ std::cout << __PRETTY_FUNCTION__ << " " << x << std::endl;};
    l(42);
    l("Hello world");
}

导致

main()::<lambda(const T&)> [with T = int] 42
main()::<lambda(const T&)> [with T = char [12]] Hello world

给出的代码格式良好,从c++ 20开始按预期工作。

每[expr.prim.lambda]:

lambda-expression:
     lambda-declaratoropt compound-statement
,,, lambda-introducer <template-parameter-list > requiresclause opt lambda-declaratoropt compound-statement

最后一行反映了这种语法。每(expr.prim.lambda)/5:

如果存在decl-specifier,则lambda是泛型lambdaA的decl- specific -seq中的占位符类型说明符lambda表达式参数声明或者如果lambda有模板参数列表