属性指定符序列(C++11 起)

来自cppreference.com
< cpp‎ | language

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

[[attr]] [[attr1, attr2, attr3(args)]] [[namespace::attr(args)]] alignas_specifier

正式而言,语法是

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

其中 attribute-list 是零或更多 attribute 的逗号分隔列表(可选地以指示包展开的省略号 ... 结束)

identifier
attribute-namespace :: identifier
identifier ( argument-list )
attribute-namespace :: identifier ( argument-list )
1) 简单属性,例如 [[noreturn]]
2) 有命名空间的属性,流入 [[gnu::unused]]
3) 有参数的属性,例如 [[deprecated("because")]]
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++ 程序的几乎所有位置,而且可应用于几乎所有事物:到类型、变量、函数、名称、代码块、整个翻译单元,不过每个特定属性仅在实现所容许处合法: [[likely]] 可能是只能与 if ,而非与类声明一同使用的属性, [[omp::parallel()]] 可能是应用到代码块或 for 循环,而非到类型 int 等的属性。(注意此二属性是虚构示例,见后述的标准与一些非标准属性)

在声明中,属性可出现在被声明实体名称前或紧在其后,这些情况下它们被结合。多数其他情形中,属性仅应用于直接前附的实体。

alignas 指定符是属性序列指定符的一部分,尽管它拥有不同语法。它可出现于 [[...]] 属性出现处,并可与它们混合(假定用于容许 alignas 处)

二个连续的方括号记号( [[ )只能出现于引入属性指定符处,或在属性参数内。

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

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

[编辑] 标准属性

C++ 标准仅定义下列属性。

[[noreturn]] 指示函数不返回。
此属性仅应用于函数声明。若声明带此属性的函数实际返回,则行为未定义。
下列标准函数拥有此属性: std::_Exitstd::abortstd::exitstd::quick_exitstd::longjmp (C++17 起)std::unexpectedstd::terminatestd::rethrow_exceptionstd::throw_with_nestedstd::nested_exception::rethrow_nested
[[carries_dependency]] 指示释放-消费 std::memory_order 中的依赖链传播出入函数,这允许编译器跳过不必要的内存栅栏指令。
此属性可出现于二种情形:

1) 它可应用于函数或 lambda 表达式的函数参数,该情况下它指示参数的初始化携带依赖进入该对象的左值到右值转换。
2) 它可作为整体应用到函数声明,该情况下它指示返回值携带依赖到函数调用表达式的求值。

此属性必须在任何翻译单元中,出现在函数或其参数之一的首个声明上。若它在另一翻译单元中,不在于函数或其参数之一的首个声明上,则程序为病态;不要求诊断。

使用示例见 std::kill_dependency

[[deprecated]](C++14)
[[deprecated("reason")]](C++14)
指示带此属性声明的名称或实体的使用是允许的,但因 reason 被不鼓励。此属性在类、 typedef 名、变量、非静态数据成员、函数、枚举及模板特化的声明中允许。声明为非 deprecated 的名称可被重声明为 deprecated 。声明为 deprecated 的名称不能通过不带此属性重新声明变得非过时。
[[fallthrough]](C++17) 出现于 switch 上其自身的一行(技术上是空语句),恰在 case 标号前。指示从前一 case 标号落下是故意的,且不该为对落下报警的编译器诊断。
[[nodiscard]](C++17) 出现于函数声明、枚举声明或类声明中。若从异于转型到 void弃值表达式调用声明为 nodiscard 的函数或以值返回声明为 nodiscard 的枚举或类的函数,则鼓励编译器发布警告。
[[maybe_unused]](C++17) 出现于类、 typedef 、变量、非静态数据成员、函数、枚举或枚举项的声明中。若编译器对未使用实体发布警告,则对任何任何声明为 maybe_unused 的实体抑制警告。
[[optimize_for_synchronized]](TM TS) 出现于函数声明的声明器中,声明必须是函数的首个声明。指示函数定义应该为来自 synchronized 语句的调用优化。尤其是,它会避免系列化一些 synchorized 块,这些块令函数调用对大多数调用,但非所有调用事务安全

[编辑] 示例

#include <cassert>
[[ noreturn ]] void f() {
  throw "error";
  // OK
}
 
[[ noreturn ]] void q(int i) {
  // 若以 <= 0 的参数调用则行为未定义
  if (i > 0) {
    throw "positive";
  }
}
 
void f(int n) {
  void g(), h(), i();
  switch (n) {
    case 1:
    case 2:
      g();
     [[fallthrough]];
    case 3: // 落下时无警告
      h();
    case 4: // 编译器可能对落下警告
      i();
      [[fallthrough]]; // 病态,不在 case 标号前
  }
}
 
struct [[nodiscard]] error_info { };
error_info enable_missile_safety_mode();
void launch_missiles();
void test_missiles() {
   enable_missile_safety_mode(); // 编译器可能对丢弃一个 nodiscard 值警告
   launch_missiles();
}
error_info& foo();
void f1() {
    foo(); // 不以值返回 nodiscard 类型,无警告
} 
 
 
[[maybe_unused]] void f([[maybe_unused]] bool thing1,
                        [[maybe_unused]] bool thing2)
{
   [[maybe_unused]] bool b = thing1 && thing2;
   assert(b); // 在 release 模式, assert 会被编译去除,而 b 不被使用
              // 无警告,因为它声明带 [[maybe_unused]]
} // 不使用参数 thing1 与 thing2 ,无警告


[编辑] 外部链接

Clang 支持的 C++ 属性

[编辑] 参阅

_NoreturnC 文档