如何将lambda的operator()
声明为noreturn
?
Ideone接受以下代码:
#include <cstdlib>
int main() {
[]() [[noreturn]] { std::exit(1); }();
return 0;
}
Clang 3.5拒绝它:
error: 'noreturn' attribute cannot be applied to types
你可以在godbolt中尝试:http://goo.gl/vsuCsF
哪一个是对的?
更新:相关的标准部分似乎是5.1.2.5,7.6.3,7.6.4,但在阅读之后,我仍然不是100%明确的(i)什么是正确的行为,(ii)如何将lambda的operator()标记为noreturn
。
答案 0 :(得分:23)
Clang是对的。属性可以属于声明的函数或其类型;两者是不同的。 [[noreturn]]
必须与函数本身相关。
// [[noreturn]] appertains to the entity that's being declared
void f [[noreturn]] (); // §8.3 [dcl.meaning]/p1:
// The optional attribute-specifier-seq following a
// declarator-id appertains to the entity that is declared."
[[noreturn]] void h (); // §7 [dcl.dcl]/p2:
// "The attribute-specifier-seq in a simple-declaration
// appertains to each of the entities declared by
// the declarators of the init-declarator-list."
// ill-formed - [[noreturn]] appertains to the type (§8.3.5 [dcl.fct]/p1:
// "The optional attribute-specifier-seq appertains to the function type.")
void g () [[noreturn]] {}
的确如果你用g ++编译它会告诉你
warning: attribute ignored [-Wattributes]
void g () [[noreturn]] {}
^
note: an attribute that appertains to a type-specifier is ignored
请注意,它不会发出g()
确实返回的警告。
由于 lambda-declarator 中的“ attribute-specifier-seq 属于相应函数调用运算符或运算符模板的类型”(§5.1.2[ expr.prim.lambda] / p5)而不是那个运算符/运算符模板本身,你不能在那里使用[[noreturn]]
。更一般地说,该语言无法将属性应用于lambda本身的operator ()
。
答案 1 :(得分:4)
因此,lambda delcarator具有以下语法:草案C ++标准部分5.1.2
Lambda表达式:
( parameter-declaration-clause ) mutableopt exception-specificationopt attribute-specifier-seqopt trailing-return-typeopt
并且noreturn属性确实是一个有效的 attribute-specifier-seq 所以从语法的角度来看,我没有看到7.6.3
Noreturn属性中的限制>它说(强调我的前进):
[...]该属性可以应用于函数中的declarator-id 声明。[...]
似乎并不禁止使用,但确实表明不允许使用。如果我们查看部分7.6.4
承载依赖关系属性,则说:
[...]该属性可以应用于a的declarator-id 函数声明或lambda [...]
中的参数声明
明确包含lamda案例的事实强烈表明,7.6.3
部分意在排除lambdas,因此clang
是正确的。作为旁注,Visual Studio也拒绝此代码。
答案 2 :(得分:3)
[C++11: 7.6.3/1]:
attribute-tokennoreturn
指定函数不返回。它应该在每个属性列表中最多出现一次,并且不存在 attribute-argument-clause 。 该属性可以应用于函数声明中的 declarator-id 。如果该函数的任何声明,则函数的第一个声明应指定noreturn
属性。指定noreturn
属性。如果在一个翻译单元中使用noreturn
属性声明了一个函数,并且在另一个翻译单元中声明了相同的函数而没有noreturn
属性,则该程序格式错误;无需诊断。
我承认,这个措辞并没有禁止该属性出现在其他地方,但是在标准中看不到任何证据的情况下,我并不认为这是为了工作与lambda声明。
因此,Clang是正确的。
它可能会或可能不会告诉there was a patch proposal to Clang to allow GCC-style noreturn
attributes on lambdas,但不是标准表格。
很遗憾,此功能未包含在GCC's list of extensions中,因此我无法确切了解此处发生了什么。