C++/属性

维基教科书,自由的教学读本
< C++
跳到导航 跳到搜索

从C++11开始,引入了属性(attribute)概念,用于编译器实现定义的类型、对象、代码等的属性。编译器可在特定于该编译器的命名空间中定义其自己的属性;但编译器只需识别标准中定义的属性。编译器忽略它们无法识别的属性值。

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

形式上的语法为:

attribute-list  		(从 C++11)
using attribute-namespace : attribute-list  		(从 C++17)

其中attribute-list是逗号分隔的序列,包含0个或多个属性,可以以省略号...结尾表示包展开(pack expansion)

属性可以为:

identifier 		例如noreturn
attribute-namespace :: identifier 	例如gnu::unused	
identifier ( argument-list ) 		例如deprecated("because")
attribute-namespace :: identifier ( argument-list ) 		

C++17开始,使用属性列表的开始处加上“using: namespace”,那么属性列表中其他的属性就不能再指定命名空间:using指定的命名空间被应用于所有属性上。例如:

using CC: opt(1), debug // 等效于 CC::opt(1), CC::debug
using CC: CC::opt(1) // 出错:不能组合使用using与作用域限定的属性

解释[编辑]

属性提供了统一的标准语法用于编译器实现相关的语言扩展,如GNU语言扩展__attribute__((...)),Microsoft扩展__declspec()等等。

属性可用于C++程序的各处,也适用于各个要素:类型、变量、函数、名字、代码块、整个编译单元,虽然每个特定属性仅适用于实现允许的地方,如expect_true只能用于if,不能用于类的声明。omp::parallel()可用于代码块或for循环,但不能用于int类型。

标准属性[编辑]

  • noreturn 函数没有return。换句话说,函数总是抛出异常。一个函数如果有该属性,它在各个编译单元的第一次声明时都要指出该属性
  • carries_dependency indicates that dependency chain in release-consume std::memory_order propagates in and out of the function
  • deprecated(C++14)
  • deprecated("reason")(C++14) 允许使用,但是不鼓励
  • fallthrough(C++17) 从前一个case标签的直落(fall through)是故意的,编译器不应该诊断为直落警告
  • nodiscard(C++17)
  • nodiscard("reason")(C++20) 鼓励编译器发出一个警告,如果返回值被丢弃
  • maybe_unused(C++17) 对可能未被使用的实体,抑制编译器警告
  • likely(C++20)
  • unlikely(C++20) 让编译器优化这种情形,该执行路径的语句比其他执行路径可能性更大或更小。
  • no_unique_address(C++20) 指出一个非静态数据成员可能与这个类的其他非静态数据成员有相同地址
  • optimize_for_synchronized(TM TS) 指出函数定义可以优化以被同步调用

例子[编辑]

[[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()
{
}