10 Declarations [dcl.dcl]

10.6 Attributes [dcl.attr]

10.6.1 Attribute syntax and semantics [dcl.attr.grammar]

Атрибуты определяют дополнительную информацию для различных исходных конструкций, таких как типы, переменные, имена, блоки или единицы перевода.

attribute-specifier-seq:
	attribute-specifier-seqopt attribute-specifier
attribute-specifier:
	[ [ attribute-using-prefixopt attribute-list ] ]
	alignment-specifier
alignment-specifier:
	alignas ( type-id ...opt )
	alignas ( constant-expression ...opt )
attribute-using-prefix:
	using attribute-namespace :
attribute-list:
	attributeopt
	attribute-list , attributeopt
	attribute ...
	attribute-list , attribute ...
attribute:
	attribute-token attribute-argument-clauseopt
attribute-token:
	identifier
	attribute-scoped-token
attribute-scoped-token:
	attribute-namespace :: identifier
attribute-namespace:
	identifier
attribute-argument-clause:
	( balanced-token-seqopt )
balanced-token-seq:
	balanced-token
	balanced-token-seq balanced-token
balanced-token:
	( balanced-token-seqopt )
	[ balanced-token-seqopt ]
	{ balanced-token-seqopt }
	any token other than a parenthesis, a bracket, or a brace

Если an attribute-specifier содержит attribute-using-prefix, attribute-listследующее, которое attribute-using-prefix не должно содержать, attribute-scoped-token и каждый attribute-tokenв, который attribute-list обрабатывается так, как если бы его identifierпрефикс былN​::​, гдеN - это attribute-namespace указанное в attribute-using-prefix. [ Note: Это правило не накладывает ограничений на то, как объект attribute-using-prefix влияет на токены в attribute-argument-clause. ] [end noteExample:

[[using CC: opt(1), debug]]         // same as [[CC​::​opt(1), CC​::​debug]]
  void f() {}
[[using CC: opt(1)]] [[CC::debug]]  // same as [[CC​::​opt(1)]] [[CC​::​debug]]
  void g() {}
[[using CC: CC::opt(1)]]            // error: cannot combine using and scoped attribute token
  void h() {}

end example]

[ Note: Для каждого отдельного атрибута balanced-token-seqбудет указана форма . ]end note

В attribute-listобъекте многоточие может отображаться только в том случае, если это attributeразрешено спецификацией. attributeС последующим многоточием являетсяpack expansion. Не , attribute-specifierчто не содержит attributes не имеет никакого эффекта. Порядок, в котором attribute-tokens появляются символы attribute-list, не имеет значения. Если a keyword или an,alternative token которое удовлетворяет синтаксическим требованиям identifier, содержится в an attribute-token, это считается идентификатором. Нет name lookup не выполняется ни с одним из идентификаторов, содержащихся в файле attribute-token. attribute-tokenОпределяет дополнительные требования к attribute-argument-clause(если таковые имеются).

Каждый из них attribute-specifier-seqотноситсяappertain к некоторому объекту или утверждению, идентифицированному синтаксическим контекстом, в котором он встречается (пункт[stmt.stmt], пункт[dcl.dcl], пункт[dcl.decl]). Если attribute-specifier-seqэлемент, принадлежащий какой-либо сущности или оператору, содержит элемент attributeили, alignment-specifierкоторый не может применяться к этой сущности или оператору, программа сформирована неправильно. Если a attribute-specifier-seq принадлежит afriend declaration, это объявление должно быть определением. Нет attribute-specifier-seqне относится к explicit instantiation.

Для attribute-token (включая attribute-scoped-token), не указанного в этом международном стандарте, поведение определяется реализацией. Все, attribute-tokenчто не распознается реализацией, игнорируется. [ Note: Каждая реализация должна выбрать отличительное имя для attribute-namespaceфайла attribute-scoped-token. ]end note

Два последовательные левые квадратные маркеры скобки должны появляться только тогда , когда внедрив attribute-specifierили в пределах balanced-token-seqот attribute-argument-clause. [ Note: Если две последовательные левые квадратные скобки появляются там, где attribute-specifierнедопустимо, программа имеет неправильный формат, даже если скобки соответствуют альтернативной грамматической постановке. ] [end noteExample:

int p[10];
void f() {
  int x = 42, y[5];
  int(p[[x] { return x; }()]);  // error: invalid attribute on a nested declarator-id and
                                // not a function-style cast of an element of p.
  y[[] { return 2; }()] = 2;    // error even though attributes are not allowed in this context.
  int i [[vendor::attr([[]])]]; // well-formed implementation-defined attribute.
}

end example]

10.6.2 Alignment specifier [dcl.align]

alignment-specifier Может быть применена к переменной или к элементу данных класса, но оно не должно быть применено к битовое поле, параметр функции или exception-declaration([except.handle]). Также alignment-specifierможет применяться к объявлению или определению класса (в elaborated-type-specifierили class-head, соответственно) и к объявлению или определению перечисления (в opaque-enum-declarationили enum-head, соответственно ([dcl.enum])). alignment-specifierМноготочием являетсяpack expansion.

Когда alignment-specifierимеет форму :alignas( constant-expression)

  • constant-expressionявляется неотъемлемой константным выражением

  • если постоянное выражение не оценивается как значение выравнивания ([basic.align]) или оценивается как расширенное выравнивание, а реализация не поддерживает это выравнивание в контексте объявления, программа имеет неправильный формат.

Элемент alignment-specifierформы имеет тот же эффект, что и ( ).alignas( type-id) alignas(​alignof( type-id)) [expr.alignof]

Требование выравнивания объекта - это строжайшее ненулевое выравнивание, указанное в нем alignment-specifiers, если таковое имеется; в противном случае alignment-specifiers не действуют.

Комбинированный эффект all alignment-specifiers в объявлении не должен указывать менее строгое выравнивание, чем выравнивание, которое потребовалось бы для объявляемого объекта, если бы все, alignment-specifiers относящееся к этому объекту, было опущено. [Example:

struct alignas(8) S {};
struct alignas(1) U {
  S s;
};  // error: U specifies an alignment that is less strict than if the alignas(1) were omitted.

end example]

Если определяющее объявление объекта имеет alignment-specifier, любое не определяющее объявление этого объекта должно либо указывать эквивалентное выравнивание, либо не иметь alignment-specifier. И наоборот, если какое-либо объявление объекта имеет alignment-specifier, каждое определяющее объявление этого объекта должно указывать эквивалентное выравнивание. Диагностика не требуется, если объявления объекта имеют alignment-specifiers разные единицы перевода. [Example:

// Translation unit #1:
struct S { int x; } s, *p = &s;

// Translation unit #2:
struct alignas(16) S;           // error: definition of S lacks alignment, no diagnostic required
extern S* p;

end example]

[ Example: Выровненный буфер с требованием выравниванияA и содержащимиN элементы типаT может быть объявлен как:

alignas(T) alignas(A) T buffer[N];

Указаниеalignas(T) гарантирует, что окончательное запрошенное выравнивание не будет слабееalignof(T), и, следовательно, программа не будет плохо сформирована. ]end example

[Example:

alignas(double) void f();                           // error: alignment applied to function
alignas(double) unsigned char c[sizeof(double)];    // array of characters, suitably aligned for a double
extern unsigned char c[sizeof(double)];             // no alignas necessary
alignas(float)
  extern unsigned char c[sizeof(double)];           // error: different alignment in declaration

end example]

10.6.3 Carries dependency attribute [dcl.attr.depend]

attribute-tokencarries_­dependency Распространения определяет зависимость в и из функций. Он должен появляться не более одного раза в каждом attribute-listи не attribute-argument-clauseдолжен присутствовать. Атрибут может быть применен к declarator-ida parameter-declarationв объявлении функции или лямбда-выражении, и в этом случае он указывает инициализацию параметра carries a dependency для каждогоlvalue-to-rvalue conversion из этих объектов. Атрибут также может применяться к declarator-idобъявлению функции, и в этом случае он указывает, что возвращаемое значение, если оно есть, несет зависимость от оценки выражения вызова функции.

Первое объявление функции должно указыватьcarries_­dependency атрибут для ее, declarator-idесли какое-либо объявление функции указывает carries_­dependency атрибут. Кроме того, первое объявление функции должно указыватьcarries_­dependency атрибут для параметра, если какое-либо объявление этой функции указываетcarries_­dependency атрибут для этого параметра. Если функция или один из ее параметров объявлен сcarries_­dependency атрибутом в своем первом объявлении в одной единице трансляции, а та же функция или один из ее параметров объявлен без carries_­dependency атрибута в своем первом объявлении в другой единице трансляции, программа имеет неправильный формат. , диагностика не требуется.

[ Атрибут не изменяет значение программы, но может привести к образованию более эффективного кода. ]Note: carries_­dependency end note

[Example:

/* Translation unit A. */

struct foo { int* a; int* b; };
std::atomic<struct foo *> foo_head[10];
int foo_array[10][10];

[[carries_dependency]] struct foo* f(int i) {
  return foo_head[i].load(memory_order_consume);
}

int g(int* x, int* y [[carries_dependency]]) {
  return kill_dependency(foo_array[*x][*y]);
}

/* Translation unit B. */

[[carries_dependency]] struct foo* f(int i);
int g(int* x, int* y [[carries_dependency]]);

int c = 3;

void h(int i) {
  struct foo* p;

  p = f(i);
  do_something_with(g(&c, p->a));
  do_something_with(g(p->a, &c));
}

carries_­dependency Атрибут функцияf означает , что возвращаемое значение несет в себе зависимость изf, так что необходимость осуществления не ограничивает порядок после возвращения изf. Реализации f и вызывающая сторона могут выбрать сохранение зависимостей вместо выдачи инструкций по упорядочиванию аппаратной памяти (также известных как заборы).

Функцияgвторой параметр «s имеетcarries_­dependency атрибут, но его первый параметр не делает. Следовательно,hпервый вызов функции g несет зависимостьg, а ее второй вызов - нет. Реализации может потребоваться вставить забор перед вторым вызовом g.

end example]

10.6.4 Deprecated attribute [dcl.attr.deprecated]

attribute-tokendeprecated Могут быть использованы для имен меток и юридических лиц, использование которых по- прежнему допускается, но не рекомендуется для какой - то причине. [ Note: В частности, deprecated подходит для имен и организаций, которые считаются устаревшими или небезопасными. ] Он должен появляться не более одного раза в каждом . Может присутствовать и, если присутствует, то она должна иметь вид:end noteattribute-listattribute-argument-clause

( string-literal )

[ В может быть использовано для объяснения обоснования устаревания и / или предложить заменяющий объект. ]Note: string-literalattribute-argument-clauseend note

Атрибут может применяться к объявлению класса typedef-name, переменной, нестатического элемента данных, функции, пространства имен, перечисления, перечислителя или специализации шаблона.

Имя или сущность, объявленные безdeprecated атрибута, позже могут быть повторно объявлены с помощью атрибута и наоборот. [ Note: Таким образом, объект, изначально объявленный без атрибута, может быть помечен как устаревший при последующем повторном объявлении. Однако после того, как объект помечен как устаревший, последующие повторные объявления не отменяют его. ] Допускаются повторные объявления с использованием разных форм атрибута (с или без или с разными ).end noteattribute-argument-clauseattribute-argument-clauses

[ Note: Реализации могут использоватьdeprecated атрибут для создания диагностического сообщения в случае, если программа обращается к имени или объекту, отличному от его объявления, после объявления, которое определяет атрибут. Диагностическое сообщение может включать в себя текст attribute-argument-clauseлюбогоdeprecated атрибута, применяемого к имени или объекту. ]end note

10.6.5 Fallthrough attribute [dcl.attr.fallthrough]

attribute-tokenfallthrough Может быть применен кnull statement; такое заявление - провальное заявление. Они attribute-tokenfallthrough должны появляться не более одного раза в каждом attribute-listи не attribute-argument-clauseдолжны присутствовать. Заявление о провале может появиться только внутри вложенногоswitch statement. Следующим оператором, который будет выполняться после оператора перехода, должен быть помеченный оператор, метка которого является меткой case или меткой по умолчанию для того жеswitch оператора. Программа плохо сформирована, если такого оператора нет.

[ Note: Использование оператора fallthrough предназначено для подавления предупреждения, которое реализация могла бы в противном случае выдать для случая или метки по умолчанию, доступной из другого случая или метки по умолчанию на некотором пути выполнения. Реализациям рекомендуется выдавать предупреждение, если оператор сбоя недоступен динамически. ]end note

[Example:

void f(int n) {
  void g(), h(), i();
  switch (n) {
  case 1:
  case 2:
    g();
    [[fallthrough]];
  case 3:                       // warning on fallthrough discouraged
    h();
  case 4:                       // implementation may warn on fallthrough
    i();
    [[fallthrough]];            // ill-formed
  }
}

end example]

10.6.6 Maybe unused attribute [dcl.attr.unused]

Значок attribute-tokenmaybe_­unused указывает на то, что имя или объект, возможно, намеренно не используются. Он должен появляться не более одного раза в каждом attribute-listи не attribute-argument-clauseдолжен присутствовать.

Атрибут может применяться к объявлению класса typedef-name, переменной, нестатического элемента данных, функции, перечисления или перечислителя.

[ Note: Для отмеченного объектаmaybe_­unusedрекомендуется, чтобы реализации не выдавали предупреждения о том, что объект не используется или что объект используется, несмотря на наличие атрибута. ]end note

Имя или сущность, объявленные безmaybe_­unused атрибута, позже могут быть повторно объявлены с атрибутом и наоборот. Сущность считается отмеченной после первого объявления, которое ее отмечает.

[Example:

[[maybe_unused]] void f([[maybe_unused]] bool thing1,
                        [[maybe_unused]] bool thing2) {
  [[maybe_unused]] bool b = thing1 && thing2;
  assert(b);
}

Реализациям рекомендуется не предупреждать о том, чтоb не используется, независимо от того, определено оно или нетNDEBUG . ]end example

10.6.7 Nodiscard attribute [dcl.attr.nodiscard]

attribute-tokennodiscard Может быть применен к declarator-id в объявлении функции или к объявлению класса или перечисления. Он должен появляться не более одного раза в каждом attribute-listи не attribute-argument-clauseдолжен присутствовать.

[ Note: Вызов nodiscard - это выражение вызова функции, которое вызывает ранее объявленную функциюnodiscardили возвращаемый тип которой, возможно, является классом с квалификацией cv или отмеченным типом перечисленияnodiscard. Появление вызова nodiscard как потенциально оцененного выражения отбрасываемого значения (пункт[expr]) не приветствуется, если явно не приведено кvoid. Реализациям рекомендуется выдавать предупреждение в таких случаях. Обычно это происходит из-за того, что отказ от возвращаемого значения вызова nodiscard имеет неожиданные последствия. ]end note

[Example:

struct [[nodiscard]] error_info { /* ... */ };
error_info enable_missile_safety_mode();
void launch_missiles();
void test_missiles() {
  enable_missile_safety_mode(); // warning encouraged
  launch_missiles();
}
error_info &foo();
void f() { foo(); }             // warning not encouraged: not a nodiscard call, because neither
                                // the (reference) return type nor the function is declared nodiscard

end example]

10.6.8 Noreturn attribute [dcl.attr.noreturn]

В attribute-tokennoreturn указывает , что функция не возвращает. Он должен появляться не более одного раза в каждом attribute-listи не attribute-argument-clauseдолжен присутствовать. Атрибут может быть применен к declarator-idв объявлении функции. Первое объявление функции должно указыватьnoreturn атрибут, если какое-либо объявление этой функции указывает noreturn атрибут. Если функция объявляется сnoreturn атрибутом в одной единице трансляции, а та же функция объявляется безnoreturn атрибута в другой единице трансляции, программа имеет неправильный формат и диагностика не требуется.

Если функцияf вызывается там, гдеf ранее была объявлена ​​сnoreturn атрибутом, и вf конечном итоге возвращается, поведение не определено. [ Note: Функция может завершиться выдачей исключения. ] [ Реализациям рекомендуется выдавать предупреждение, если отмеченная функция может вернуться. ]end noteNote: [[noreturn]] end note

[Example:

[[ noreturn ]] void f() {
  throw "error";                // OK
}

[[ noreturn ]] void q(int i) {  // behavior is undefined if called with an argument <= 0
  if (i > 0)
    throw "positive";
}

end example]