Атрибуты в C++ 1/2.
Начнём со стандартных.
С точки зрения синтаксиса поддерживается два основных варианта:
[[attribute_name]] // C++11
[[using attribute-namespace: attribute_list]] // C++17Из примеров с cppreference ещё можно увидеть такое:
- атрибуты с аргументами:
[[deprecated(“text”)]];- с неймспейсом:
[[gnu::unused]].Атрибуты можно применять к чему угодно: переменным, типам, функциям, классам, блокам кода и целым translation units. Но конечно это должно согласовываться с его реализацией.
[[noreturn]] говорит, что функция не возвращает control flow кода. Например она вызывает std::terminate, бросает исключение, содержит бесконечный цикл и т.д. В C можно использовать _Noreturn или noreturn для аналогичного.[[carries_dependency]] может использоваться в случаях, когда у вас memory order consume. Я вообще в этих ваших многопоточках не оч шарю, но говорят, что введение такого понятия не самое удачное решение. Мб подскажете адекватные кейсы использования?[[deprecated]], [[deprecated(“message”)]] говорит, что какой-то объект является deprecated (обычно компиляторы выдают ворнинги при использовании помеченых штук).[[fallthrough]] говорит, что провал в следующий case в switch является намеренным -> компилятор не будет подсказывать ворнингами об этом.[[nodiscard]], [[nodiscard(“message”)]] применяются к функции и означают, что не стоит игнорировать её возвращаемое значение. Если да, получите ворнинг.[[maybe_unused]] говорит, что используемый объект может быть просто объявлен, но нигде в коде не заюзан. Если атрибут есть, вы не получите ворнинга. Удобно иногда, когда пишешь код частями и хочешь проверять, компилится ли, наставить их всему, что мешает. Потом с продвижением по решению таски поубирать. Или когда у вас какой-то общий интерфейс, но не все аргументы нужны для новой реализации.[[likely]], [[unlikely]] говорят, что некоторый code flow выполняется чаще/реже. Соответственно компилятор может использовать эти знания и оптимизировать hot path. Или наоборот. Мб вы знаете кейсы, когда это прям помогает? Имхо компиляторы сейчас неплохо с такими вещами и так справляются.[[no_unique_address]] говорит, что член класса может не обладать уникальным адресом в памяти, из-за чего несколько членов класса потенциально могут пересекаться в памяти. Подробнее расскажу про него вместе с empty base class optimization чуть позже.В msvc игнорится (даже с С++20), потому надо юзать
[[msvc::no_unique_address]].[[assume]] говорит, что некоторое выражение, которое вы в него засунете, будет true c момента указания атрибута. Это может помочь компилятору провести какие-то оптимизации (опять не уверен, что это сильно поможет): int x = f();
[[assume(x > 0)]];
// далее это утверждение может использоваться для более эффективных оптимизацийint z = x;
[[assume((h(), x == z))]]; // после вызова h() переменные всё ещё будут равны[[assume((g(z), true))]]; // g(z) вернёт trueЕщё примерчики можно посмотреть на cppref.
using в атрибутах это про сокращение записи. Например это может быть полезно для нестандартных атрибутов. Вместо [[gnu::always_inline]] [[gnu::hot]] [[gnu::const]]можно писать
[[using gnu: always_inline, hot, const]]Тут и
using, и сразу несколько атрибутов в одном attribute-specifier (это [[]]).