命名空间
变体
操作

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

来自 cppreference.com
< cpp‎ | 语言
 
 
C++ 语言
 
 
属性
 

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

内容

[编辑] 语法

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

(自 C++20 起)

[编辑] 标准属性

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

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

标准属性也不能在语义上被忽略:在删除所有特定标准属性实例的情况下,对包含属性的原始程序执行符合行为将构成符合行为。

[[noreturn]](C++11) 表示该函数不返回。
(属性说明符)[编辑]
[[carries_dependency]](C++11) 表示在发布-使用 std::memory_order 中,依赖链会传播到函数内部和外部。
(属性说明符)[编辑]
[[deprecated]](C++14)
[[deprecated("reason")]](C++14)
表示允许使用带有此属性的声明的名称或实体,但出于某些 reason 原因,不建议这样做。
(属性说明符)[编辑]
[[fallthrough]](C++17) 表示从上一个 case 标签的贯穿是故意的,并且不应被警告贯穿的编译器诊断出来。
(属性说明符)[编辑]
[[maybe_unused]](C++17) 如果存在,则会抑制编译器对未使用实体的警告。
(属性说明符)[编辑]
[[nodiscard]](C++17)
[[nodiscard("reason")]](C++20)
鼓励编译器在返回值被丢弃时发出警告。
(属性说明符)[编辑]
[[likely]](C++20)
[[unlikely]](C++20)
表示编译器应该针对通过语句的执行路径比任何其他执行路径更可能或更不可能的情况进行优化。
(属性说明符)[编辑]
[[no_unique_address]](C++20) 表示非静态数据成员不必具有与其类中所有其他非静态数据成员不同的地址。
(属性说明符)[编辑]
[[assume(expression)]](C++23) 指定在给定点 expression 将始终计算为 true
(属性说明符)[编辑]
[[indeterminate]](C++26) 指定如果对象未初始化,则它具有不确定的值。
(属性说明符)[编辑]
[[optimize_for_synchronized]](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 每个标准属性都需要在 attribute-list 中最多出现一次 不需要

[编辑] 另请参见

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

[编辑] 外部链接

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