Spec-Zone.ru › C++

Последовательность спецификаторов атрибутов (since C++11)

Вводит атрибуты, поведение которых определяется реализацией, для типов, объектов, кода и т. д.

Синтаксис

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

где attribute-list — последовательность из нуля или более элементов attribute, разделённых запятыми (возможно, заканчивающаяся многоточием ..., обозначающим раскрытие пакета параметров)

identifier (1)
attribute-namespace :: identifier (2)
identifier ( argument-list (необязательно) ) (3)
attribute-namespace :: identifier ( argument-list (необязательно) ) (4)

где attribute-namespace — это identifier, а argument-list — последовательность токенов со сбалансированными круглыми, квадратными и фигурными скобками (balanced-token-seq).

1) Простой атрибут, например [[noreturn]].
2) Атрибут с пространством имён, например [[gnu::unused]].
3) Атрибут с аргументами, например [[deprecated("because")]].
4) Атрибут с пространством имён и списком аргументов.

Если using namespace: появляется в начале списка атрибутов, никакие другие атрибуты в этом списке не могут указывать пространство имён: пространство имён, заданное в using, применяется ко всем атрибутам списка:

[[using CC: opt(1), debug]] // same as [[CC::opt(1), CC::debug]]
[[using CC: CC::opt(1)]] // error: cannot combine using and scoped attribute
(since C++17)

Если каждый элемент спецификатора атрибута начинается с =, спецификатор атрибута вместо этого вводит аннотации. Атрибуты (не начинающиеся с =) и аннотации (начинающиеся с =) нельзя смешивать в одном спецификаторе атрибута.

(since C++26)

Пояснение

Атрибуты предоставляют единый стандартный синтаксис для расширений языка, поведение которых определяется реализацией, таких как расширения языков GNU и IBM __attribute__((...)), расширение Microsoft __declspec() и т. д.

Атрибут можно использовать почти в любом месте программы на C++ и применять почти ко всему: к типам, переменным, функциям, именам, блокам кода и целым единицам трансляции. Однако каждый конкретный атрибут допустим только там, где его разрешает реализация: [[expect_true]] мог бы быть атрибутом, который можно использовать только с if, но не с объявлением класса. [[omp::parallel()]] мог бы быть атрибутом, применимым к блоку кода или циклу for, но не к типу int и т. д. (обратите внимание, что эти два атрибута — вымышленные примеры; стандартные и некоторые нестандартные атрибуты перечислены ниже).

В объявлениях атрибуты могут располагаться как перед объявлением целиком, так и непосредственно после имени объявляемой сущности; в последнем случае они объединяются. В большинстве других ситуаций атрибуты применяются к непосредственно предшествующей сущности.

Спецификатор alignas является частью последовательности спецификаторов атрибутов, хотя его синтаксис отличается. Он может располагаться там же, где и атрибуты [[...]], и сочетаться с ними (при условии, что используется в месте, где разрешён alignas).

Два следующих друг за другом токена левой квадратной скобки ([[) могут встречаться только при введении спецификатора атрибута или внутри аргумента атрибута.

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

Помимо перечисленных ниже стандартных атрибутов, реализации могут поддерживать произвольные нестандартные атрибуты с поведением, определяемым реализацией. Все атрибуты, неизвестные реализации, игнорируются без ошибки.(since C++17)

Атрибут без attribute-namespace, а также attribute-namespace, имя которого равно std или std и за которым следуют одна или несколько цифр, зарезервированы для будущей стандартизации. То есть каждый нестандартный атрибут принадлежит пространству имён attribute-namespace, предоставляемому реализацией, например [[gnu::may_alias]], [[clang::trivial_abi]] и [[msvc::noop_dtor]].

(since C++20)

Стандартные атрибуты

Следующие атрибуты определены стандартом C++.

Стандартные атрибуты нельзя синтаксически игнорировать: они не должны содержать синтаксических ошибок, должны применяться к правильной цели, а сущности в аргументах должны быть использованы по правилу ODR.

Стандартные атрибуты нельзя игнорировать и семантически: поведение, полученное после удаления всех экземпляров конкретного стандартного атрибута, должно соответствовать стандарту для исходной программы с этим атрибутом.

[[noreturn]]
(C++11)
указывает, что функция не возвращает управление
(спецификатор атрибута)
[[carries_dependency]]
(C++11)(удалён в C++26)
указывает, что цепочка зависимостей в модели памяти release-consume std::memory_order проходит через функцию в обоих направлениях
(спецификатор атрибута)
[[deprecated]][[deprecated("reason")]]
(C++14)(C++14)
указывает, что использование имени или сущности, объявленной с этим атрибутом, разрешено, но не рекомендуется по некоторой причине
(спецификатор атрибута)
[[fallthrough]]
(C++17)
указывает, что переход к следующей метке case из предыдущей метки case является намеренным и не должен вызывать предупреждение компилятора, если тот предупреждает о таком переходе
(спецификатор атрибута)
[[maybe_unused]]
(C++17)
подавляет предупреждения компилятора о неиспользуемых сущностях, если таковые имеются
(спецификатор атрибута)
[[nodiscard]][[nodiscard("reason")]]
(C++17)(C++20)
побуждает компилятор выдать предупреждение, если возвращаемое значение отбрасывается
(спецификатор атрибута)
[[likely]][[unlikely]]
(C++20)(C++20)
указывает, что компилятору следует оптимизировать программу для случая, когда путь выполнения через оператор более или менее вероятен, чем любой другой путь выполнения
(спецификатор атрибута)
[[no_unique_address]]
(C++20)
указывает, что нестатический член данных не обязан иметь адрес, отличный от адресов всех остальных нестатических членов данных своего класса
(спецификатор атрибута)
[[assume(expression)]]
(C++23)
указывает, что выражение всегда будет вычисляться в true в заданной точке
(спецификатор атрибута)
[[indeterminate]]
(C++26)
указывает, что объект имеет неопределённое значение, если он не инициализирован
(спецификатор атрибута)
[[optimize_for_synchronized]]
(TM TS)
указывает, что определение функции следует оптимизировать для вызова из синхронизированного оператора
(спецификатор атрибута)

Примечания

Наличие каждого отдельного атрибута на заданной платформе можно проверить с помощью макроса препроцессора __has_cpp_attribute.

Макрос проверки возможностей Значение Стандарт Возможность
__cpp_attributes 200809L (C++11) Атрибуты
__cpp_namespace_attributes 201411L (C++17) Атрибуты для пространств имён

Пример

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

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были ретроактивно применены к ранее опубликованным стандартам C++.

Отчёт об ошибке Применяется к Опубликованное поведение Корректное поведение
CWG 2079 C++11 [[ нельзя было использовать внутри аргумента атрибута разрешено
CWG 2538 C++11 не было ясно, можно ли синтаксически игнорировать стандартные атрибуты запрещено
CWG 2695 C++11 не было ясно, можно ли семантически игнорировать стандартные атрибуты запрещено
P2156R1 C++11 каждый стандартный атрибут должен был встречаться в attribute-list не более одного раза не обязательно

См. также

__has_cpp_attribute — проверяет наличие атрибута
Документация по C для последовательности спецификаторов атрибутов

Внешние ссылки

1. Атрибуты в GCC. Эти атрибуты можно использовать как [[gnu::...]], см. Stack Overflow.
2. Атрибуты в Clang.
3. Атрибуты в MSVC.

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/attributes

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API