属性说明符序列(C23 起)
对类型、对象、表达式等引入实现定义的属性。
[[
attr]]
[[
attr1, attr2, attr3(
args)
]]
[[
属性前缀::
attr(
arg)
]]
正式而言,语法是
[[ 属性列表 ]]
|
(C23 起) | ||||||||
其中 属性列表 是零或多个 属性记号 的逗号分隔列表
标准属性 | (1) | ||||||||
属性前缀 :: 标识符
|
(2) | ||||||||
标准属性 ( 实参列表 )
|
(3) | ||||||||
属性前缀 :: 标识符 ( 实参列表 )
|
(4) | ||||||||
解释
属性为各种由实现定义的语言扩展(例如 GNU 与 IBM 的语言扩展 __attribute__((...))
,微软的语言扩展 __declspec()
等)提供了统一化的语法。
属性可用在 C 程序中的几乎所有位置,而且可应用于几乎所有事物:类型、变量、函数、名字、代码块、整个翻译单元,不过每个特定的属性都仅在实现所容许之处有效:[[expect_true]]
可能是只能与 if,而非与类声明一同使用的属性,[[omp::parallel()]]
可能是应用到代码块或 for 循环,而非到类型 int
等的属性。(请注意这两个属性只是虚构的例子,有关标准与一些非标准属性,见下文)
在声明中,属性可出现在整个声明之前,或直接跟在被声明实体的名字之后,这些情况下它们被组合起来。大多数其他情形中,属性应用于直接位于其之前的实体。
不同于 C++ 中的 alignas 与 [[noreturn]]
, _Alignas
与 _Noreturn
说明符不是属性说明符序列的一部分。
两个连续的方括号记号([[
)只能出现于引入属性说明符之处,或在属性实参之内。
除了以下所列出的标准属性之外,实现还可能支持任意拥有由实现定义的行为的非标准属性。所有实现所未知的属性均被忽略,且不产生错误。
每个 标准属性 均为标准化保留。即每个非标准属性均由实现提供的 属性前缀 冠以前缀,例如 [[gnu::may_alias]]
与 [[clang::no_sanitize]]
。
标准属性
C++ 标准仅定义下列属性。每个名字形如 attr
的标准属性亦能拼写成 __attr__
而其含义不变。
[[deprecated]] (C23)[[deprecated("reason")]] (C23)
|
指示允许使用声明有此属性的名称或实体,但因 reason 而不鼓励使用。 |
[[fallthrough]] (C23)
|
指示从前一 case 标号直落是有意的,而在发生直落时给出警告的编译器不应该为此诊断。 |
[[nodiscard]] (C23)[[nodiscard("reason")]] (C23)
|
若返回值被舍弃,则鼓励编译器发布警告。 |
[[maybe_unused]] (C23)
|
抑制编译器在未使用实体上的警告,若存在。 |
属性测试
__has_c_attribute( 属性记号 )
|
|||||||||
检查 属性记号 所指名的属性记号的存在。
对于标准属性,它将展开成该属性被添加到工作草案中时的年份和月份(见下表),特定于厂商的属性则以某个非零整数常量确定。
能在
#if 与
#elif 的表达式中展开 __has_c_attribute
。
#ifdef 、
#ifndef 和 defined 把它当做已定义的宏,但不能在别处使用它。
属性记号 | 属性 | 值 | 标准 |
---|---|---|---|
deprecated
|
[[deprecated]]
|
201904L | (C23) |
fallthrough
|
[[fallthrough]]
|
201904L | (C23) |
maybe_unused
|
[[maybe_unused]]
|
201904L | (C23) |
nodiscard
|
[[nodiscard]]
|
202003L | (C23) |
示例
[[gnu::always_inline]] [[gnu::hot]] [[gnu::const]] [[nodiscard]] int f(void); // 声明 f 带四个属性 [[gnu::always_inline, gnu::const, gnu::hot, nodiscard]] int f(void); // 同上,但用含四个属性的单个属性说明符 int f(void) { return 0; } int main(void) { }