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

时间:2016-10-09 21:10:00

标签: c++ gcc lambda clang language-lawyer

我正在尝试使用lambdas和编译器,因为another question就在这里 我刚刚意识到(并且确实非常正常)以下代码是有效的:

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

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

通过查看标准(以及工作草案)我无法解释的事实是GCC(6.1)编译了以下片段(clang 3.9没有):

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

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

3 个答案:

答案 0 :(得分:21)

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

  

lambda-introducer lambda-declarator opt compound-statement

其中&#34; lambda-introductioncer&#34; [],包含一个可选的&#34; lambda-capture&#34; &#34; lambda-declarator opt &#34; 是以&#34;(parameter-declaration-clause)&#34;开头的东西。

[]<typename>(){}

不符合该要求,因为lambda介绍器和lambda声明符之间存在某些内容,因此它不是有效的lambda表达式。

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

由于此标记为,因此我点击了GNU C++ extensions列表。我没有找到任何可以使GNU C ++中的语法合法的扩展。

然而,根据this proposal(P0428R0)的第4节,它建议将模板化的lambdas添加到C ++中,gcc在2009年得到了上述论文的实验性实现。这可能解释了为什么gcc不能解决这个问题。抱怨在这里。

答案 1 :(得分:2)

它似乎是一个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

答案 2 :(得分:0)

自C ++ 20起,给定的代码格式正确,并且可以正常工作。

[expr.prim.lambda]

  

lambda-expression
lambda-introducer lambda-declarator opt 复合语句
   lambda简介 <    template-parameter-list > 需要子句 opt lambda声明符 opt 复合语句 < / p>

最后一行反映了这种语法。根据{{​​3}}:

  

如果存在 decl-specifier ,则lambda是通用lambda    decl-specifier-seq 中的 placeholder-type-specifier    lambda-expression parameter-declaration ,或者lambda具有 template-parameter-list < / p>