Vai*_*Man 6 c++ lambda attributes language-lawyer
CppCon2022 的这个演讲在 08:40 说:
在 C++23 之前,您可以为lambda 表达式生成的函数对象指定属性。
例如:
Run Code Online (Sandbox Code Playgroud)auto a = [] () [[deprecated]] { return 42; };
然而,clang 有理由拒绝这段代码:
“已弃用”属性无法应用于类型
而 gcc 和 msvc 很乐意接受它,而不给出使用警告。
https://godbolt.org/z/Wqhq7hP6s
cppreference.com介绍 lambda 表达式的语法为(部分引用):
[捕获] (参数)规格要求(可选) { body }
- specs - 由specifiers、exception、attr和trailing-return-type按顺序组成;这些组件中的每一个都是可选的
- attr - 为闭包类型的函数调用运算符或运算符模板的类型 提供属性规范。如此指定的任何属性都不属于函数调用运算符或运算符模板本身,而是属于其类型。(例如,不能使用 [[noreturn]] 属性。)
那么,这是怎么回事?[[deprecated]]lambda 表达式生成的函数对象上的属性的语义是什么 ?
这看起来像是基于特定于实现的(不合格)行为的错误。版本 9 之前的 GCC 确实处理了[[deprecated]]该位置的属性,如视频中所述。更高版本警告被[[deprecated]]忽略,目前它根本不警告,这似乎是一种回归,另请参阅此处关于不同属性但相同问题的错误报告。
正如您还引用 cppreference 一样,该属性属于函数调用运算符的类型,请参阅[expr.prim.lambda.closure]/4,并且[[deprecated]]可能不适用于类型,请参阅[dcl.attr.deprecated] /2 . 因此,程序应该是格式错误的,编译器应该提供诊断。
然而,在 C++20 后的草案中,lambda 声明符的decl-specifier-seq中的另一个可能的attribute-specifier-seq仍然存在歧义。这已随CWG 2509删除,但是即使没有删除,它也适用于decl-specifier形式的类型,请参阅[dcl.spec.general]/1,但不能有任何类型lambda 声明符中的说明符。
[[deprecated]]可以位于声明之前或声明器 ID 之后,以应用于正在声明的变量:
[[deprecated]] auto a = [] () { return 42; };
Run Code Online (Sandbox Code Playgroud)
或者
auto a [[deprecated]] = [] () { return 42; };
Run Code Online (Sandbox Code Playgroud)
在这种情况下,它应该警告任何进一步的使用a(无论是否在通话中),尽管对使用[[deprecated]]实体使用的警告只是建议的做法,而不是严格要求,请参阅[dcl.attr.deprecated]/4。
不可能将属性添加到 lambda 的闭包类型,或者通常添加到从 lambda 纯右值创建的对象。在此处的特定情况下,该对象与变量重合,但一般来说,放置一个对象a没有多大意义。[[deprecated]]对象在运行时存在。编译器无法在编译时警告它们的使用。它只能在编译时对变量(和函数等)的使用发出警告。
在 C++23 中,lambda 声明符之前的属性 (before ()) 属于函数调用运算符本身是正确的,因此[[noreturn]]视频中的属性是有意义的。然而,[[deprecated]]如果目的是避免调用 lambda,而不是其他用途,也应该属于那里,例如:
auto a = [] [[deprecated]] () {return 42;};
auto b = a; // no warning
b(); // warning
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
293 次 |
| 最近记录: |