C++/特性

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