Последовательность спецификаторов атрибутов(начиная с C++11)
Вводит определяемые реализацией атрибуты для типов, объектов, кода и т.д.
Синтаксис
[[ список-атрибутов ]]
|
(начиная с C++11) | ||||||||
[[ using пространство-имён-атрибутов : список-атрибутов ]]
|
(начиная с C++17) | ||||||||
где список-атрибутов представляет собой разделённую запятыми последовательность из нуля или более атрибутов (возможно, заканчивающуюся многоточием ..., указывающее на расширение пакета)
| идентификатор | (1) | ||||||||
пространство-имён-атрибутов :: идентификатор
|
(2) | ||||||||
идентификатор ( список-аргументов (необязательно) )
|
(3) | ||||||||
пространство-имён-атрибутов :: идентификатор ( список-аргументов (необязательно) )
|
(4) | ||||||||
где пространство-имён-атрибутов это идентификатор, а список-аргументов это последовательность токенов, в которой круглые и фигурные скобки сбалансированы (balanced-token-seq).
[[noreturn]].[[gnu::unused]].[[deprecated("причина")]].|
Если [[using CC: opt(1), debug]] // то же, что и [[CC::opt(1), CC::debug]]
[[using CC: CC::opt(1)]] // ошибка: нельзя сочетать using и атрибут области видимости
|
(начиная с C++17) |
Объяснение
Атрибуты обеспечивают единый стандартный синтаксис для языковых расширений, определяемых реализацией, таких как языковые расширения GNU и IBM __attribute__((...)), расширение Microsoft __declspec(), и т.д.
Атрибут может использоваться почти везде в программе на C++ и может применяться почти ко всему: к типам, к переменным, к функциям, к именам, к блокам кода, к целым единицам трансляции, хотя каждый конкретный атрибут действителен только там, где он необходим и где он разрешён реализацией: [[expect_true]] может быть атрибутом, который можно использовать только с if, а не с объявлением класса, [[omp::parallel()]] может быть атрибутом, который применяется к блоку кода или к циклу for, но не к типу int, и т.д. (обратите внимание, что эти два атрибута являются вымышленными примерами, смотрите ниже стандартные и некоторые нестандартные атрибуты)
В объявлениях атрибуты могут стоять как перед всем объявлением, так и сразу после имени объявляемой сущности, и в этом случае они объединяются. В большинстве других ситуаций атрибуты применяются к непосредственно предшествующему объекту.
Спецификатор alignas является частью последовательности спецификаторов атрибутов, хотя он имеет другой синтаксис. Он может появляться там, где появляются атрибуты [[...]], и может смешиваться с ними (при условии, что он используется там, где разрешён alignas)
Два последовательных маркера левой квадратной скобки ([[) могут появляться только при введении спецификатора-атрибута или внутри аргумента атрибута.
void f()
{
int y[3];
y[[] { return 0; }()] = 1; // ошибка
int i [[cats::meow([[]])]]; // OK
}
Помимо стандартных атрибутов, перечисленных ниже, реализации могут поддерживать произвольные нестандартные атрибуты с поведением, определяемым реализацией. Все атрибуты, неизвестные реализации, игнорируются без возникновения ошибки. (начиная с C++17)
|
Атрибут без атрибута-пространства-имён и атрибут-пространства-имён, чье имя либо |
(начиная с C++20) |
Стандартные атрибуты
Следующие атрибуты определены стандартом C++.
Стандартные атрибуты нельзя синтаксически игнорировать: они не могут содержать синтаксические ошибки, должны применяться к правильной цели, а сущности в аргументах должны использоваться использоваться ODR.
Стандартные атрибуты также нельзя семантически игнорировать: поведение при удалении всех экземпляров определённого стандартного атрибута соответствует поведению исходной программы с присутствующим атрибутом.
[[noreturn]](C++11)
|
указывает, что функция не возвращает значение (спецификатор атрибута) |
[[carries_dependency]](C++11)
|
указывает, что цепочка зависимостей в выпуске, использующем std::memory_order, распространяется в функцию и из неё (спецификатор атрибута) |
[[deprecated]](C++14)[[deprecated]](C++14)
|
указывает, что использование имени или объекта, объявленного с этим атрибутом, разрешено, но не рекомендуется по некоторым причинам (спецификатор атрибута) |
[[fallthrough]](C++17)
|
указывает, что провал от предыдущей метки case является преднамеренным и не должен диагностироваться компилятором, который предупреждает о провале (спецификатор атрибута) |
[[nodiscard]](C++17)[[nodiscard]](C++20)
|
побуждает компилятор выдавать предупреждение, если возвращаемое значение отбрасывается (спецификатор атрибута) |
[[maybe_unused]](C++17)
|
подавляет предупреждения компилятора о неиспользуемых сущностях, если таковые имеются (спецификатор атрибута) |
[[likely]](C++20)[[unlikely]](C++20)
|
указывает, что компилятор должен оптимизировать для случая, когда путь выполнения через оператор более или менее вероятен, чем любой другой путь выполнения (спецификатор атрибута) |
[[no_unique_address]](C++20)
|
указывает, что нестатический элемент данных не должен иметь адрес, отличный от всех других нестатических элементов данных его класса (спецификатор атрибута) |
[[assume]](C++23)
|
указывает, что выражение всегда будет оцениваться как true в данной точке(спецификатор атрибута) |
[[optimize_for_synchronized]](ТС TM)
|
указывает, что определение функции должно быть оптимизировано для вызова из синхронизированного оператора (спецификатор атрибута) |
Примечание
Наличие каждого отдельного атрибута на конкретной платформе можно проверить с помощью макроса препроцессора __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(); // объявляет f с четырьмя атрибутами
[[gnu::always_inline, gnu::const, gnu::hot, nodiscard]]
int f(); // то же, что и выше, но использует один спецификатор атрибутов,
// который содержит четыре атрибута
// C++17:
[[using gnu : const, always_inline, hot]] [[nodiscard]]
int f[[gnu::always_inline]](); // атрибут может появиться в нескольких спецификаторах
int f() { return 0; }
int main() {}
Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
| Номер | Применён | Поведение в стандарте | Корректное поведение |
|---|---|---|---|
| CWG 2079 | C++11 | [[ не может появляться внутри аргумента атрибута
|
позволено |
| CWG 2538 | C++11 | было неясно, можно ли синтаксически игнорировать стандартные атрибуты | запрещено |
| CWG 2695 | C++11 | было неясно, можно ли семантически игнорировать стандартные атрибуты | запрещено |
| WG не указан | C++11 | каждый стандартный атрибут должен был появляться не более одного раза в списке-атрибутов |
не требуется |
Смотрите также
__has_cpp_attribute - проверяет наличие атрибута
| |
Документация C по Последовательность спецификаторов атрибутов
|
Внешние ссылки
| 1. | Атрибуты в GCC. Эти атрибуты можно использовать как [[gnu::...]], смотрите здесь
|
| 2. | Атрибуты в Clang |
| 3. | Атрибуты в MSVC. |