C/C++ programming: attributes (attr), specifiers

Attributes

effect

  • Introduce implementation-defined attributes for types, objects, codes, etc.
  • Attributes provide a unified syntax for various implementation-defined language extensions (such as GNU and IBM's language extension attribute ((...)), Microsoft's language extension __declspec(), etc.).
  • Attributes can be used in almost all places in a C++ program, and can be applied to almost everything: types, variables, functions, names, code blocks, entire translation units, but each specific attribute is only valid where the implementation allows:
    • [[expect_true]] may be an attribute that can only be used with if, not with class declarations
    • [[omp::parallel()]] may be applied to code blocks or for loops, rather than to attributes of type int, etc.
  • Official document

grammar

[[attr]] [[attr1, attr2, attr3(args)]] [[namespace::attr(args)]] alignas-说明符 (1)
[[ 属性列表 ]] (2)
[[ using 属性命名空间 : 属性列表 ]] (3)

(1) Example

[[gnu::always_inline]] [[gnu::hot]] [[gnu::const]] [[nodiscard]]
inline int f1(); // 声明 f 带四个属性

(2) Example

[[gnu::always_inline, gnu::const, gnu::hot, nodiscard]]
int f2(); // 同上,但使用含有四个属性的单个属性说明符

(3) Examples:

[[using gnu : const, always_inline, hot]] [[nodiscard]]
int f[[gnu::always_inline]](); // 属性可出现于多个说明符中

Specifier

Specifiers include the following:

  • typedef specifier. If it exists, the entire declaration is a typedef declaration, and each declarator introduces a new type name, not an object or function
  • Function specifiers ( inline, virtual, explicit ) are only allowed in function declarations. Since C++17, inline is also allowed to be used on variable declarations
  • The friend specifier is allowed in class and function declarations
  • Since C++11, the constexpr specifier is only allowed to be used in variable definitions, function and function template declarations, and declarations of static data members with literal types.
  • Starting from C++20, the consteval specifier is only allowed to be used in functions and function template declarations.
  • Starting from C++20, the constinit specifier is only allowed to be used in variable declarations with static or thread storage duration. A statement sequence descriptor at most allowed constexpr, consteval constinit and one specifier.
  • Storage class specifiers ( register, static, thread_local (since C++11), extern, mutable ). Only one storage class specifier is allowed, but thread_local can appear with extern or static.
  • Type specifiers (also called type specifier sequences). The type specifier is a sequence of space-separated specifiers (only the following specifiers can be included)
    • Class specifiers: class, struct, union
    • Enumeration specifier: enum
    • Simple type specifier
      • char、char8_t (C++20 起)、char16_t、char32_t (C++11 起)、wchar_t、bool、short、int、long、signed、unsigned、float、double、void
      • auto, decltype specifier
      • Previously declared class name, enumeration name, typedef name, (since C++11) type alias
      • Template name with template arguments, template name without template arguments
    • Detailed type specifier
      • Keywords class, struct, or union, followed by identifiers that have been previously defined as class, struct, or union names
      • The keyword class, struct, or union, followed by the template name followed by the template argument, which has been previously defined as the name of the class template
      • The keyword enum is followed by an identifier previously defined as an enumeration name
    • typename specifier
    • cv qualifier specifier

Declaration specifier sequence

  • The sequence of declaration specifiers (referred to as declaration specifiers) is a sequence of specifiers separated by blanks , in any order
  • Only one type specifier is allowed in each declaration specifier sequence , with the following exceptions:
    • const 、volatile Can be combined with any type specifier outside of itself
    • signedOr unsignedcan and char, long, short int, or combinations thereof.
    • shortOr longcan be combined with int
    • longCan be combined with long. (Since C++11)
      • The only specifier that allows two occurrences in the declaration specifier sequence is long (which can appear twice). All other repetitions, such as const static const or virtual inline virtual are errors (since C++17).
  • Attributes can appear in the declaration specifier, in which case they apply to the type determined by the specifier before it.

Declarator

The declaration specifier sequence and the declarator are two different things, see the example

class C {
    
    
    std::string member; // 声明说明符序列 为 "std::string"
                        // 声明符 为 "member"
} obj, *pObj(&obj);
// 声明说明符序列 为 "class C { std::string member; }"
// 声明符 "obj" 定义 C 类型的对象
// 声明符 "*pObj(&obj)" 声明并初始化指向 C 的指针
 
int a = 1, *p = nullptr, f(), (*pf)(double);
// 声明说明符序列 为 int
// 声明符 a=1 定义并初始化 int 类型的变量
// 声明符 *p=NULL 定义并初始化 int* 类型的变量
// 声明符 (f)() 声明(但不定义)不接收参数并返回 int 的函数
// 声明符 (*pf)(double) 定义指向接收 double 并返回 int 的函数的指针
 
int (*(*foo)(double))[3] = nullptr;
// decl-specifier-seq 为 int
// 1. 声明符 "(*(*foo)(double))[3]" 是数组声明符;
//    所声明类型是“int 的 3 元素数组 /嵌套声明符/ ”
// 2. 嵌套声明符是 "(*(*foo)(double))",它是指针声明符
//    所声明类型是“int 的 3 元素数组 的指针 /嵌套声明符/”
// 3. 嵌套声明符是 "(*foo)(double)",它是函数声明符
//    所声明类型是“以 int 的 3 元素数组 的指针 为返回值的接受一个 double 参数的函数 /嵌套声明符/”
// 4. 嵌套声明符是 "(*foo)",它是(带括号,如函数声明符语法所要求的)指针声明符。
//    所声明类型是“以 int 的 3 元素数组 的指针 为返回值的接受一个 double 参数的函数 的指针 /嵌套声明符/”
// 5. 嵌套声明符是 "foo",它是标识符。
// 该声明声明了对象 foo,其类型为“以 int 的 3 元素数组 的指针 为返回值的接受一个 double 参数的函数 的指针”
// 初始化器 "= nullptr" 提供此指针的初值。

example

other

Limited is the scope resolution operator in front of the unqualified identification expression::

Guess you like

Origin blog.csdn.net/zhizhengguan/article/details/114985589