如何将 lambda 的运算符 () 声明为 noreturn?
How to declare a lambda's operator() as noreturn?
如何将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 的运算符(( 标记为 noreturn
.
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 中的属性说明符 seq 适用于相应函数调用运算符或运算符模板的类型"(§5.1.2 [expr.prim.lambda]/p5(,而不是该运算符/运算符模板本身,因此您不能在那里使用[[noreturn]]
。更一般地说,该语言无法将属性应用于 lambda 本身的operator ()
。
因此,lambda delcarator 具有以下语法,草稿C++ Lambda 表达式的标准部分5.1.2
:
( parameter-declaration-clause ) mutableopt exception-specificationopt attribute-specifier-seqopt trailing-return-typeopt
noreturn 属性确实是一个有效的属性说明符-seq,所以从语法的角度来看,我没有看到它所说的 Noreturn 属性第 7.6.3
节的限制(强调我的(:
[...]该属性可以应用于函数中的声明符 ID 声明。[...]
这似乎并不禁止您使用,但它确实表明它是不允许的。如果我们看一下第 7.6.4
携带依赖属性的部分,它说:
[...]该属性可以应用于 函数声明或 lambda 中的参数声明[...]
它明确包括 lamda 案例这一事实强烈表明第 7.6.3
节旨在排除 lambda,因此clang
是正确的。作为旁注,Visual Studio也拒绝了这段代码。
[C++11: 7.6.3/1]:
属性令牌noreturn
指定函数不返回。它在每个属性列表中最多出现一次,并且不应存在任何属性参数子句。该属性可以应用于函数声明中的声明符 id。如果函数的任何声明指定了noreturn
属性,则该函数的第一个声明应指定noreturn
属性。如果在一个翻译单元中使用noreturn
属性声明函数,而在另一个翻译单元中声明同一函数而不声明noreturn
属性,则程序格式不正确;无需诊断。
我承认这种措辞并不禁止该属性出现在其他地方,但考虑到在标准中的任何地方都没有看到任何证据,我认为这不适用于 lambda 声明。
因此,Clang是正确的。
它可能会也可能不会告诉 Clang 有一个补丁提案,允许 lambda 上的 GCC 风格的noreturn
属性,但不是标准形式。
不幸的是,此功能未包含在GCC的扩展列表中,因此我无法真正看到这里到底发生了什么。
在 2022 年阅读本文,以下内容似乎对我有用。
希望它能帮助任何偶然发现这篇文章的人。
#include <cstdlib>
int main() {
[]() __attribute__((__noreturn__)) { std::exit(1); }();
return 0;
}
另一个创建宏的版本:
#define NO_RETURN __attribute__((__noreturn__))
#include <cstdlib>
int main() {
[]() NO_RETURN { std::exit(1); }();
return 0;
}
- .cpp和.h文件中的模板专用化声明
- 未在作用域中声明unordered_map
- C++避免重复声明的语法是什么
- 如何确保C++函数在定义之前声明(如override关键字)
- 错误:未在此范围内声明'reverse'
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 为什么在定义函数之前先声明它
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- #ifdef和未声明的标识符
- 没有显式声明的int[]中的foreach
- 在基于范围的for循环中使用结构化绑定声明
- 在将变量声明为引用时,堆在释放后使用
- C++:无法访问声明的受保护成员
- 为什么我不能在一个类的不同行中声明和定义成员变量?
- 我不明白为什么我声明一个空的内部结构并将其传递给构造函数
- 使用cmake从源代码构建MySQL连接器/C++失败(与以前的声明冲突)
- 在函数内部的声明中初始化数组,并在外部使用它
- 在可疑的情况下发出叮当警告:函数'foo'可以用属性"noreturn"声明吗?
- 如何将 lambda 的运算符 () 声明为 noreturn?
- 错误:声明'noreturn'不应返回的函数