如何将 lambda 的运算符 () 声明为 noreturn?

How to declare a lambda's operator() as noreturn?

本文关键字:声明 noreturn 运算符 lambda      更新时间:2023-10-16

如何将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;
}