Skip to content

Attributes

  • are formal notations to enable/disable compiler warnings
  • express additional constraints
  • give a hint to the compiler to optimize the code
  • can be specified for types, variables, functions, names, code blocks
  • Syntax: [[attributeName]] int MyFunc();
  • possible attributes: maybe_unused, nodiscard, fallthrough, deprecated, noreturn, likely, unlikely, no_unique_address

[[maybe_unused]]
allows definition of variable, function, class, type without using it. Useful for function parameters which are used only conditionally in special configurations:

void DoSomething([[maybe_unused]] std::string in_msg)
{
    #ifdef DEBUG
        Trace(msg);
    #endif
}

[[nodiscard(“optional reason”]]
force using/checking the return value of a function

class MyContainer
{
public:
  [[nodiscard]] bool empty() const;
};

If you have a special definition for your return type you can force the checking of return value also by applying the attribute directly to the return type:

enum class [[nodiscard("do not ignore return value")]] MyReturnType
{
    eOK,
    eWARNING,
    eERROR
}

You can give an explicit hint e.g. when an allocated object is ignored:

[[nodiscard(“this is a memory leak”)]] T* CreateObject()
{
    return new T;
}

[[fallthrough]]
suppress compiler warnings for case statements without break:

switch (someInt)
{
    case 1:
        doSomething();
        break;
    case 2: 
        doSoemthingElse();
        [[fallthrough]];
    case 3: [[fallthrough]];
    case 4:
        finalReaction();
        break;
}

[[deprecated]]
Do not use the corresponding name/function

[[noreturn]]
indicates that a function will not return:

[[noreturn]] void MyFunc()
{
    ...
    throw SomeException();}
}

Remark: undefined behaviour if the function returns!

[[likely]] or [[unlikely]]
Gives a hint to the compiler that the corresponding code branch is more/less probable and the code can be optimized:

if (someCondition)
{
    [[likely]] DoThis();
}
else
{
    DoThat();
}

[no_unique_address]
the data member has no own address (e.g. because it is empty) and the compiler can optimize by occupying no memory:

struct Empty{};
struct SomeOtherStruct
{ int x{}; [[no_unique_address]] Empty e{}; // has same address as x }