命名空间
变体
操作

属性说明符序列 (C++11 起)

来自 cppreference.cn
< cpp‎ | 语言
 
 
C++ 语言
 
 
属性
(C++23)
(C++11)(直至 C++26)
(C++14)
(C++20)
(C++17)
(C++11)
(C++20)
 

引入用于类型、对象、代码等的实现定义属性。

目录

[编辑] 语法

[[ attribute-list ]] (C++11 起)
[[ using attribute-namespace : attribute-list ]] (C++17 起)

其中 attribute-list 是由零个或多个 attribute 组成的逗号分隔序列(可能以省略号 ... 结尾,表示包扩展

标识符 (1)
attribute-namespace :: identifier (2)
identifier ( argument-list(可选) ) (3)
attribute-namespace :: identifier ( argument-list(可选) ) (4)

其中 attribute-namespace 是一个 identifierargument-list 是一个标记序列,其中圆括号、方括号和花括号是平衡的 (balanced-token-seq)。

1) 简单属性,例如 [[noreturn]]
2) 带命名空间的属性,例如 [[gnu::unused]]
3) 带参数的属性,例如 [[deprecated("because")]]
4) 既有命名空间又有参数列表的属性。

如果 using namespace: 出现在属性列表的开头,则属性列表中的其他属性不能指定命名空间:using 中指定的命名空间适用于所有这些属性。

[[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 的属性以及其名称为 stdstd 后跟一个或多个数字的 attribute-namespace 保留用于未来的标准化。也就是说,每个非标准属性都位于实现提供的 attribute-namespace 中,例如 [[gnu::may_alias]][[clang::trivial_abi]][[msvc::noop_dtor]]

(C++20 起)

[编辑] 标准属性

以下属性由 C++ 标准定义。

标准属性不能在语法上被忽略:它们不能包含语法错误,必须应用于正确的目标,并且参数中的实体必须是 ODR-use

标准属性也不能在语义上被忽略:移除特定标准属性的所有实例后的行为,对于带有该属性的原始程序而言,仍将是符合规范的行为。

(C++11)
指示函数不返回
(属性说明符)[编辑]
(C++11)(C++26 中移除)
指示在 release-consume std::memory_order 中,依赖链在函数内外传播
(属性说明符)[编辑]
[[deprecated]][[deprecated("reason")]]
(C++14)(C++14)
指示允许使用此属性声明的名称或实体,但由于某些 reason 而不鼓励使用
(属性说明符)[编辑]
(C++17)
指示从前一个 case 标签的直落是故意的,不应被警告直落的编译器诊断
(属性说明符)[编辑]
(C++17)
抑制编译器关于未使用实体的警告(如果有)
(属性说明符)[编辑]
[[nodiscard]][[nodiscard("reason")]]
(C++17)(C++20)
鼓励编译器在返回值被丢弃时发出警告
(属性说明符)[编辑]
(C++20)(C++20)
指示编译器应优化语句执行路径比其他任何执行路径更有可能或更不可能的情况
(属性说明符)[编辑]
指示非静态数据成员不必具有与其类中所有其他非静态数据成员不同的地址
(属性说明符)[编辑]
[[assume(expression)]]
(C++23)
指定 expression 在给定点将始终评估为 true
(属性说明符)[编辑]
(C++26)
指定如果对象未初始化,则它具有不确定值
(属性说明符)[编辑]
指示应优化函数定义,以从同步语句中调用
(属性说明符)[编辑]

[编辑] 注意

给定平台上每个单独属性的存在可以通过 __has_cpp_attribute 预处理器宏进行检查。

功能测试宏 标准 特性
__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++ 标准。

缺陷报告 应用于 发布时的行为 正确的行为
CWG 2079 C++11 [[ 不能出现在属性参数内部 允许
CWG 2538 C++11 不清楚标准属性是否可以在语法上被忽略 已禁止
CWG 2695 C++11 不清楚标准属性是否可以在语义上被忽略 已禁止
P2156R1 C++11 每个标准属性都要求在 attribute-list 中最多出现一次 未要求

[编辑] 另请参阅

__has_cpp_attribute - 检查属性的存在
C 文档 用于 属性说明符序列

[编辑] 外部链接

1.  GCC 中的属性。这些属性可以作为 [[gnu::...]] 使用,参见 SO
2.  Clang 中的属性.
3.  MSVC 中的属性.