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

来自cppreference.com
< cpp‎ | language


 
 
C++ 语言
 
 
属性
(C++23)
(C++14)
(C++20)
(C++17)
(C++11)
(C++20)
 

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

语法

[[ 属性列表 ]] (C++11 起)
[[ using 属性命名空间 : 属性列表 ]] (C++17 起)

其中属性列表 是由逗号分隔的零或更多个属性 的序列(可以以指示包展开的省略号 ... 结束)

标识符
属性命名空间 :: 标识符
标识符 ( 实参列表 (可选) )
属性命名空间 :: 标识符 ( 实参列表 (可选) )

其中属性命名空间为一个标识符,而实参列表为其中圆括号、方括号和花括号平衡出现的记号序列(平衡记号序列)。

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

如果 using namespace: 出现在属性列表开头,那么属性列表中的其他属性均无法指定命名空间:由 using 所指定的命名空间会应用到所有这些属性:

[[using CC: opt(1), debug]] // 同 [[CC::opt(1), CC::debug]]
[[using CC: CC::opt(1)]] // 错误:不能结合 using 和有作用域属性
(C++17 起)

解释

属性为各种由实现定义的语言扩展(例如 GNU 与 IBM 的语言扩展 __attribute__((...)),微软的语言扩展 __declspec() 等)提供了统一的语法。

属性可用在 C++ 程序中的几乎所有位置,而且可应用于几乎所有事物:类型、变量、函数、名字、代码块、整个翻译单元,不过每个特定的属性都只在实现允许范围内有效:[[expect_true]] 可能是只能与 if,而非与类声明一同使用的属性,[[omp::parallel()]] 可能是应用到代码块或 for 循环,而非到类型 int 等的属性。(请注意以上两个属性只是虚构的例子,有关标准与一些非标准属性请见下文。)

在声明中,属性既可以在整个声明之前出现,也可以直接跟在被声明实体的名字之后,这些情况下它们被组合起来。大多数其他情形中,属性应用于直接位于其之前的实体。

虽然 alignas 说明符拥有不同的语法,但它是属性序列说明符的一部分。它可以在 [[...]] 属性出现的地方出现,并可以和它们混合(假设此处允许使用 alignas)。

两个连续的方括号记号([[)只能出现于引入属性说明符之处,或在属性实参之内。

void f()
{
    int y[3];
    y[[] { return 0; }()] = 1; // 错误
    int i [[cats::meow([[]])]]; // OK
}

除了以下所列出的标准属性之外,实现还可能支持拥有由实现定义的行为的任意非标准属性。所有实现所未知的属性均被忽略,且不产生错误。 (C++17 起)

属性命名空间 的属性与名字以 stdstd 后随一或多个数字的属性命名空间 为未来标准化保留。即每个非标准属性都在实现提供的 属性命名空间 中,例如 [[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("原因")]](C++14)
指示以此属性声明的名字或实体,允许使用但因某种 原因 而不鼓励使用
(属性指示符)
[[fallthrough]](C++17) 指示从前一 case 标号的直落是故意的,且会警告直落的编译器不应当对此诊断
(属性指示符)
[[maybe_unused]](C++17) 抑制对于未使用实体的编译器警告,如果有
(属性指示符)
[[nodiscard]](C++17)
[[nodiscard("原因")]](C++20)
鼓励编译器在返回值被丢弃时发出警告
(属性指示符)
[[likely]](C++20)
[[unlikely]](C++20)
指示编译器应当针对此种情况进行优化:通过某条语句的执行路径比其他任何执行路径更可能或不可能发生
(属性指示符)
[[no_unique_address]](C++20) 指示一个非静态数据成员不必具有与类中的其他所有非静态数据成员都不同的地址
(属性指示符)
[[assume(表达式)]](C++23) 指示 表达式 在给定的位置永远为 true
(属性指示符)
[[indeterminate]](C++26) 指示对象在未初始化时具有不确定值
(属性指示符)
[[optimize_for_synchronized]](TM TS) 指示函数定义应当为从同步语句中调用的情况优化
(属性指示符)

注解

预处理宏 __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(); // 声明 f 带四个属性
 
[[gnu::always_inline, gnu::const, gnu::hot, nodiscard]]
int f(); // 同上,但使用含有四个属性的单个属性说明符
 
// C++17:
[[using gnu : const, always_inline, hot]] [[nodiscard]]
int f[[gnu::always_inline]](); // 属性可出现于多个说明符中
 
int f() { return 0; }
 
int main() {}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
CWG 2079 C++11 [[ 不能在属性实参之内出现 可以出现
CWG 2538 C++11 不明确标准属性是否能在语法上被忽略 禁止忽略
CWG 2695 C++11 不明确标准属性是否能在语义上被忽略 禁止忽略
P2156R1 C++11 每个标准属性在一个属性列表 中最多只能出现一次 不限制次数

参阅

__has_cpp_attribute - 检查某个属性是否存在

外部链接

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