属性说明符序列 (自 C++11 起)
为类型、对象、代码等引入实现定义的属性。
目录 |
[编辑] 语法
[[ attribute-list ]] |
(自 C++11 起) | ||||||||
[[ using attribute-namespace : attribute-list ]] |
(自 C++17 起) | ||||||||
其中 attribute-list 是零个或多个 attribute 的逗号分隔序列(可能以省略号 ...
结尾,表示 参数包展开)
identifier | (1) | ||||||||
attribute-namespace :: identifier |
(2) | ||||||||
identifier ( argument-list (可选) ) |
(3) | ||||||||
attribute-namespace :: identifier ( argument-list (可选) ) |
(4) | ||||||||
其中 attribute-namespace 是一个 identifier,而 argument-list 是括号、方括号和大括号平衡的标记序列(balanced-token-seq)。
如果 [[using CC: opt(1), debug]] // same as [[CC::opt(1), CC::debug]] [[using CC: CC::opt(1)]] // error: cannot combine using and scoped attribute |
(自 C++17 起) |
[编辑] 解释
属性为实现定义的语言扩展提供了统一的标准语法,例如 GNU 和 IBM 语言扩展 __attribute__((...))
、Microsoft 扩展 __declspec()
等。
属性几乎可以在 C++ 程序的任何地方使用,并且可以应用于几乎所有事物:类型、变量、函数、名称、代码块、整个翻译单元,尽管每个特定的属性仅在实现允许的地方有效:[[expect_true]]
可能是一个只能与 if
一起使用的属性,而不能与类声明一起使用。[[omp::parallel()]]
可能是一个应用于代码块或 for
循环的属性,但不能应用于 int
类型等(请注意,这两个属性是虚构的示例,请参阅下文了解标准属性和一些非标准属性)。
在声明中,属性可以出现在整个声明之前和直接在声明实体的名称之后,在这种情况下,它们会被组合起来。在大多数其他情况下,属性应用于紧邻的前一个实体。
`alignas` 说明符是属性说明符序列的一部分,尽管它具有不同的语法。它可以出现在 `[[...]]` 属性出现的位置,并且可以与它们混合使用(前提是它在允许使用 alignas 的地方使用)。
两个连续的左方括号标记 (`[[`) 只能在引入属性说明符或在属性参数内部出现。
void f() { int y[3]; y[[] { return 0; }()] = 1; // error int i [[cats::meow([[]])]]; // OK }
除了下面列出的标准属性外,实现可能支持具有实现定义行为的任意非标准属性。所有实现未知的属性都将被忽略,而不会导致错误。(自 C++17 起)
没有 attribute-namespace 的属性和名称为 `std` 或 `std` 后跟一个或多个数字的 attribute-namespace 保留用于未来的标准化。也就是说,每个非标准属性都在实现提供的 attribute-namespace 中,例如 `[[gnu::may_alias]]`、`[[clang::trivial_abi]]` 和 `[[msvc::noop_dtor]]`。 |
(自 C++20 起) |
[编辑] 标准属性
以下属性由 C++ 标准定义。
标准属性在语法上不能被忽略:它们不能包含语法错误,必须应用于正确的目标,并且参数中的实体必须是 ODR 使用。
标准属性在语义上也不能被忽略:移除特定标准属性的所有实例后的行为对于存在属性的原始程序来说仍然是符合标准的行为。
[[noreturn]] (C++11) |
指示函数不返回 (属性说明符) |
(C++11)(在 C++26 中移除) |
指示 release-consume std::memory_order 中的依赖链在函数内外传播 (属性说明符) |
[[deprecated]] [[deprecated("reason")]] (C++14)(C++14) |
指示允许使用使用此属性声明的名称或实体,但不建议出于某些 reason 使用 (属性说明符) |
[[fallthrough]] (C++17) |
指示从前一个 case 标签的 fall through 是有意的,并且不应被发出 fall-through 警告的编译器诊断 (属性说明符) |
[[maybe_unused]] (C++17) |
如果存在未使用的实体,则抑制编译器警告 (属性说明符) |
鼓励编译器在返回值被丢弃时发出警告 (属性说明符) | |
指示编译器应针对语句的执行路径比任何其他执行路径或多或少可能的情况进行优化 (属性说明符) | |
(C++20) |
指示非静态数据成员不必具有与其类的所有其他非静态数据成员不同的地址 (属性说明符) |
[[assume(expression)]] (C++23) |
指定 表达式 在给定点始终求值为 true (属性说明符) |
[[indeterminate]] (C++26) |
指定对象如果未初始化,则具有不确定值 (属性说明符) |
(TM TS) |
指示应针对从 同步语句 的调用优化函数定义 (属性说明符) |
[编辑] 注解
可以使用 __has_cpp_attribute
预处理器宏检查给定平台上是否存在每个单独的属性。
特性测试宏 | 值 | Std | 特性 |
---|---|---|---|
__cpp_attributes |
200809L |
(C++11) | 属性 |
__cpp_namespace_attributes |
201411L |
(C++17) | 命名空间的属性 |
[编辑] 示例
[[gnu::always_inline]] [[gnu::hot]] [[gnu::const]] [[nodiscard]] inline int f(); // declare f with four attributes [[gnu::always_inline, gnu::const, gnu::hot, nodiscard]] int f(); // same as above, but uses a single attr specifier that contains four attributes // C++17: [[using gnu : const, always_inline, hot]] [[nodiscard]] int f[[gnu::always_inline]](); // an attribute may appear in multiple specifiers int f() { return 0; } int main() {}
[编辑] 缺陷报告
以下行为变更缺陷报告已追溯应用于先前发布的 C++ 标准。
DR | 应用于 | 已发布行为 | 正确行为 |
---|---|---|---|
CWG 2079 | C++11 | [[ 不能出现在属性参数内部 |
允许 |
CWG 2538 | C++11 | 尚不清楚标准属性是否可以在语法上被忽略 | 禁止 |
CWG 2695 | C++11 | 尚不清楚标准属性是否可以在语义上被忽略 | 禁止 |
P2156R1 | C++11 | 每个标准属性都必须在 属性列表 中最多出现一次 | 不需要 |
[编辑] 参见
__has_cpp_attribute - 检查属性是否存在 | |
C 文档:属性说明符序列
|
[编辑] 外部链接
1. | GCC 中的属性。这些属性可以用作 [[gnu::...]] ,参见 SO。 |
2. | Clang 中的属性. |
3. | MSVC 中的属性. |