Since C++17, there is now a standardized way to politely suggest the compiler to stop yelling aboud unused entities. When applying this to variables, functions, and old-skool type-aliases, we have to use the expected syntax which comes in the form:
[[maybe_unused]] int x;
[[maybe_unused]] void f();
[[maybe_unused]] typedef void t;
Nothing strange here. However, when applying this attribute-specifier to structs, enums, and especially modern-day type-aliases, we have to resort to all kinds of gobbledygook to make it work:
struct [[maybe_unused]] s;
union [[maybe_unused]] u;
enum class [[maybe_unused]] e;
using a [[maybe_unused]] = void; // what's up with this?
What is the reason for the odd placement of the [[maybe_unused]]
attribute for type-aliases? Could it really not be any other way?
Because it’s like a spiral: inner attributes are applied to inner names/types, outer attributes are applied to outer names.
[[maybe_unused]] struct [[maybe_unused]] s {} s_;
// ^^^^^^^^^^^^^^^^-^
// applied to the type
//
// ^^^^^^^^^^^^^^^^------------------------------^^
// applied to the variable
[[maybe_unused]] struct s1; // invalid, there is no variable name
[[maybe_unused]] struct {} s2; // valid, there is a variable name
As for the alias-declaration:
using identifier [attribute-specifier-seq] = defining-type-id ;
no clue how to justify that.
The ability to place an attribute-specifier-seq in an alias declaration was added by the resolution to CWG1042. Unfortunately, when I looked through the CWG minutes, I couldn’t find any recorded discussion about the placement of the attribute-specifier-seq. But it’s pretty easy to come up with a guess as to why it goes after the identifier: to mirror the syntax of a typedef declaration:
typedef void a [[maybe_unused]];
A typedef declaration is a type of simple-declaration, that is, it has the same grammatical structure as the declaration of one or more variables or functions. In simple-declarations, attributes follow the name of the entity declared:
int f [[deprecated]] (), x [[maybe_unused]];
Note that f
is a deprecated function taking no arguments and returning int
, and x
is a possibly intentionally unused variable of type int
.
You can also put an attribute at the beginning of a simple-declaration, but in that case it appertains to all entities declared in the declaration, whereas putting the attribute after the declarator-id makes it appertain to only a single entity.
Since an alias-declaration only declares one entity at a time, the hypothetical syntax
[[maybe_unused]] using a = void;
would have been reasonable too, and would have the same meaning; perhaps CWG simply did not wish to provide two ways of writing the same thing.
I’m not sure offhand about type aliases, but I can guess the others are because putting the attribute in front is already taken by the potential variable declaration (e.g.,
[[maybe_unused]] struct s {} obj;
would affectobj
).