Where can I use alignas() in C++11? - c++

In an effort to standardize my code and make it more portable, I replaced
#ifdef __GNUC__
typedef __attribute__((aligned(16))) float aligned_block[4];
#else
typedef __declspec(align(16)) float aligned_block[4];
#endif
with
typedef float alignas(16) aligned_block[4];
in C++11. However, gnu (4.8) doesn't like that but complains
test.cc:3:9: warning: attribute ignored [-Wattributes]
typedef float alignas(16) aligned_block[4];
^
test.cc:3:9: note: an attribute that appertains to a type-specifier is ignored
whereas clang 3.2 creates no warning (even with -Weverything -Wno-c++98-compat -pedantic).
So I wonder whether my code above is correct and, more generally, where alignas() can and cannot be placed.
EDIT (Apr 2013):
The relevant article from the standard is 7.6.2, in particular 7.6.2.1
An alignment-specifier may be applied to a variable or to a class data member, but it shall not be applied to a bit-field, a function parameter, the formal parameter of a catch clause (15.3), or a variable declared with the register storage class specifier. An alignment-specifier may also be applied to the declaration of a class or enumeration type. An alignment-specifier with an ellipsis is a pack expansion (14.5.3).
as already dug out by Red XIII. However, I'm not expert enough to know what this means for my test above.
If the fact that clang accepts my attribute means anything, it's perhaps worth mentioning that when trying to use a using directive instead of a typedef, clang also complains. Also, contrary to a statement in an earlier version of this question, gcc does not only warn, but indeed ignores my wish for alignment.

I think you just placed the alignas in the wrong position. If you move it directly after the identifier, both GCC and Clang are happy and apply the alignment:
typedef float aligned_block alignas(16) [4];
typedef float aligned_block [4] alignas(16);
this is also true if you use using, where the difference also becomes more apparent. Here are two versions that are not accepted by GCC (warning, alignment ignored):
using aligned_block = float alignas(16)[4];
using aligned_block = float[4] alignas(16);
and here's the accepted one:
using aligned_block alignas(16) = float[4];
I think that GCC applies
7.1.3 The typedef specifier [dcl.typedef]
2 A typedef-name can also be introduced by an alias-declaration. The identifier following the using keyword becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that typedef-name. It has the same semantics as if it were introduced by the typedef specifier. [...]
(emphasis mine)
The above is quite clear for using, the rules for typedef are spread through several paragraphs, including at the end of §8.3/1, where you find:
8.3 Meaning of declarators [dcl.meaning]
1 [...] The optional attribute-specifier-seq following a declarator-id appertains to the entity that is declared.
(again, emphasis mine)
Update: The above answer concentrated on where the alignas has to be placed, not on its exact meaning. After thinking about it some more, I still think that the above should be valid. Consider:
7.6.2 Alignment Specifier [dcl.align]
1An alignment-specifier may be applied to a variable or to a class data member, but it shall not be applied to a bit-field, a function parameter, an exception-declaration (15.3), or a variable declared with the register storage class specifier. An alignment-specifier may also be applied to the declaration or definition of a class (in an elaborated-type-specifier (7.1.6.3) or class-head (Clause 9), respectively) and to the declaration or definition of an enumeration (in an opaque-enum-declaration or enum-head, respectively (7.2)). An alignment-specifier with an ellipsis is a pack expansion (14.5.3).
It lists cases where it can be clearly applied and it lists cases where it clearly can not be applied. The above question's example is neither.
One could also argue that the type alias created by typedef or using is carrying the alignment specification as part of the aliased type. This alias can than be used to create a variable, etc. as allowed by 7.6.2p1 but not to create a variable with register, etc.
In that sense I think that the attribute specifier is applied (in the sense of 7.6.2) in a deferred way and thus OPs example should still be valid when the alignment specification is put in the syntactically correct place.

You cannot apply an alignment to a typedef. In the C++ model of alignment specifiers, the alignment is an inseparable part of the type itself, and a typedef does not create a new type (it only provides a new name for an existing type) so it is not meaningful to apply an alignment specifier in a typedef declaration.
From [dcl.align] (7.6.2)p1:
An alignment-specifier may be applied to a variable or to a class data member [...]. An alignment-specifier may also be applied to the declaration or definition of a class (in an elaborated-type-specifier (7.1.6.3) or class-head (Clause 9), respectively) and to the declaration or definition of an enumeration (in an opaque-enum-declaration
or enum-head, respectively (7.2)).
These are the only places where the standard says an alignment-specifier (alignas(...)) may be applied. Note that this does not include typedef declarations nor alias-declarations.
Per [dcl.attr.grammar] (7.6.1)p4:
If an attribute-specifier-seq that appertains to some entity or statement contains an attribute that is not allowed to apply to that entity or statement, the program is ill-formed.
This wording was intended to apply to alignas as well as the other forms of attribute that may appear within an attribute-specifier-seq, but was not correctly updated when alignment switched from being a "real" attribute to being a different kind of attribute-specifier-seq.
So: your example code using alignas is supposed to be ill-formed. The C++ standard does not currently explicitly say this, but it also does not permit the usage, so instead it currently would result in undefined behavior (because the standard does not define any behavior for it).

Draft C++11 standard http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf says about it (Alignment-specifier is of the form alignas ( assignment-expression )):
7.6.2 Alignment specifier [dcl.align]
1 An alignment-specifier may be applied to a variable or to a class data member, but it shall not be applied
to a bit-field, a function parameter, the formal parameter of a catch clause (15.3), or a variable declared
with the register storage class specifier. An alignment-specifier may also be applied to the declaration of
a class or enumeration type. An alignment-specifier with an ellipsis is a pack expansion.
I found this original proposal http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1877.pdf , it says:
The alignment-specifier does not become part of the type, but it is possible to create a class type
with aligned member variable(s).
with this example:
// Wrong attempt: Listing 6)
typedef double align_by<0x10000> hwDoubleVector; // Error!
Void clear(hwDoubleVector &toClear, unsigned size);
Looks like it's illegal to use it with typedef.

Try:
typedef float alignas(16) aligned_block[4];

Related

Is it legal to use a different class-key in a declaration and the definition of a class-name?

Does the standard (as of C++20) explicitly or implicitly allow using a different class-key when (forward-)declaring a class-name than when defining it?
For the purpose of this question class-key shall be limited to class or struct, excluding union.
In other words, is this legal:
struct C;
class C{};
class S;
struct S{};
An answer should explicitly refer to the C++20 standard (or a suitable draft).
I couldn't find anything in the entire [class] section.
The only indication I could find is in [decl.type.elab.6] which first states:
The class-key or enum keyword present in the elaborated-type-specifier shall agree in kind with the declaration to which the name in the elaborated-type-specifier refers.
But to me it is unclear what kind means in this context. I suppose enum and struct are different kinds but are struct and class different kinds? I don't know. Anyway after some unrelated points about friends it goes on to say:
Thus, in any elaborated-type-specifier, the enum keyword shall be used
to refer to an enumeration ([dcl.enum]), the union class-key shall be
used to refer to a union ([class.union]), and either the class or
struct class-key shall be used to refer to a non-union class
([class.pre]).
(emph added)
This sort of sounds as if struct and class were interchangeable, but I'm not sure about it.
According to code explorer it appears to be generally accepted by compilers.
Non-Duplicates
I do not believe Mixing class and struct answers the question. Due to its age, it talks about a different version of the standard. Also, the one answer that actually quotes the standard does not convince: The quoted paragraph has a lot of ambiguity and does not address the question asked here.
Forward declaration as struct vs class has no answers actually bothering to prove their assertions by citation.
Changing struct to class (and other type changes) and ABI/code generation Asks about two definitions with different class-keys. Its answer does not apply here.
The standard explains this in 9.2.8.3.3 and clarifies it in the example, as Peter already pointed out in a comment to your question:
[...] either the class or struct class-key shall be used to refer to a non-union class
[...]
struct S { } s;
class S* p = &s; // OK
The compilers agree, as can be seen by the warning clang generates:
warning: 'C' defined as a struct here but previously declared as a class; this is valid, but may result in linker errors under the Microsoft C++ ABI [-Wmismatched-tags]
GCC has a faq entry:
Because it is not a bug, hence the warning is just noise. This is a
dumb warning that only exists because the MS compiler has a bug that
treats struct and class differently in mangled names. GCC (and Clang)
correctly implement the C++ standard which says it doesn't matter.

Return alias identificator instead of type in typeid(SOME_TYPE).name()

In the following example
template <typename T>
void foo() {
const char* name = typeid(T).name();
std::cout << name;
}
the variable 'name' will be initialized by type 'T' name. It is very convinient if we need to print this template type name. But, if we have the alias:
using shortTypeName = std::smth::smth_else::smth_more;
in the result of the call
foo<shortTypeName>();
will be printed 'std::smth::smth_else::smth_more'. And I need to print exactly the alias name, but not the type it is defined. Can somebody give an advice, how I can do this?
... alias identificator ...
There's no such thing, at least not after compilation. It's just syntactic sugar and doesn't exist in any sense in the final executable.
The only way to grab the local name of a type (as opposed to the implementation-defined and probably-mangled typeid name) is with a stringize/stringify macro.
For future reference, this should eventually be possible when the Reflection TS lands - but I don't yet know whether to expect that to look like reflexpr(T).get_name(), or std::meta::name_of(^T), or something else again.
Can somebody give an advice, how I can do this?
The language does not support a mechanism to do this.
What you have is simply a type alias.
From http://en.cppreference.com/w/cpp/language/type_alias:
A type alias declaration introduces a name which can be used as a synonym for the type denoted by type-id. It does not introduce a new type and it cannot change the meaning of an existing type name.
You can't. Because a type alias is transparent: It is just a synonym for a new type, not a new type. As an implementation detail it doesn't even get mangled in the type system because it's not a type.
§7.1.3 The typedef specifier [dcl.typedef]
[...] A name declared with the typedef specifier becomes a typedef-name . Within the scope of its declaration, a typedef-name is
syntactically equivalent to a keyword and names the type associated
with the identifier in the way described in Clause 8. A typedef-name
is thus a synonym for another type. A typedef-name does not
introduce a new type the way a class declaration (9.1) or enum
declaration does.
A typedef-name can also be introduced by an alias-declaration . The identifier following the using keyword becomes a typedef-name and the
optional attribute-specifier-seq following the identifier appertains
to that typedef-name . It has the same semantics as if it were
introduced by the typedef specifier. In particular, it does not
define a new type and it shall not appear in the type-id .
typeid(T).name(); is pretty much useless anyway. Until we have proper introspection in C++ you have to resort to hacks to get what you want (macros, intrusive techniques or external code generator tools).

Legality of empty, unnamed enumeration specifier

In the example in §7.5 (C++14) one finds:
enum {}; // ill-formed
But, technically speaking, I think the code is valid.enum {} is an enum-specifier, and so, it's a type-specifier, which is a decl-specifier, and thus, it is a simple-declaration with an omitted init-declarator-list. And this is accepted by §7.5. Note that the identifier is optional for an unscoped enumeration. Also, clang compiles this with a warning.
Edit
In relation to the answers mentioning that the *decl-specifier-seq* shall introduce one or more names into the program, or shall redeclare a name introduced by a previous declaration, I show below a typedef declaration that compiles, but whose decl-specifier-seq doesn't introduce any name in the declaration:
typedef class {} A;
In the C++14 FD, right above your example, it is explained why the declaration is ill-formed:
In a simple-declaration, the optional init-declarator-list can be
omitted only when declaring a class (Clause 9) or enumeration (7.2)
[…]
In such cases, the decl-specifier-seq shall introduce one or more
names into the program, or shall redeclare a name introduced by a
previous declaration.
Hence
enum {} e;
enum {a};
Are valid - our quote does not apply to the first declaration as it includes an init-declarator, and the second one introduces the name a as an enumerator. Note that GCC won't compile the first declaration, which is presumably a bug.
You also mentioned the quote
If the enumerator-list is empty, the underlying type is as if the
enumeration had a single enumerator with value 0.
This makes a statement about the underlying type, not the enumeration itself, and is thus irrelevant for this matter.
Why does typedef class {} A; compile?
A is an init-declarator. Yes, it is - [dcl.dcl]/9:
If the decl-specifier-seq contains the typedef specifier, the
declaration is called a typedef declaration and the name of each
init-declarator is declared to be a typedef-name
I.e. the names declared as typedef-names are the init-declarators, by this definition. Hence there is an init-declarator-list, and our above quote isn't applicable.
If you look through the standard, you'll find quite a few things that would be accepted at a purely syntactical level, but are prohibited by the text. This is just one of many instances of that basic idea.
Many of these situations are pretty obvious. Let's consider a really trivial one: a floating point number. Using a syntactical notation similar to that of the standard we could get something like:
"-"opt digits opt "."opt digits opt ("e" "-"opt digits)opt
Everything there is "optional". That doesn't, however, mean that nothingness should be taken as a number. Nor does it mean that (for example) .e is a valid floating point number. It does mean that almost any individual piece can be omitted if some of the others are present. You don't need digits both before and after the decimal point, so each is optional in itself--but one or the other has to be present, so 1. and .1 are both valid, but just . isn't. Likewise, the . is optional as well--something like 1e50 is a perfectly valid floating point literal, even though it doesn't contain a . anywhere.
Those limitations are expressed in the text associated with the syntactic notation itself. What's allowed (or not) has to based on everything taken together, not just on one piece in isolation.
There is clear written in the Standard that (7 Declarations)
...In such cases, and except for the declaration of an unnamed bit-field (9.6), the decl-specifier-seq shall introduce one or more
names into the program, or shall redeclare a name introduced by a
previous declaration.
This declaration
enum {}; // ill-formed
does not satisfy the requirement. It introduces neither name into the program.
As for typedef(s) then
7.1.3 The typedef specifier 1 Declarations containing the decl-specifier typedef declare identifiers that can be used later
for naming 94)

const typedef; in C and C++

What was the original reason behind allowing statements like the following in C and C++?
const typedef;
It doesn't seem to make any practical sense.
Also, you can do this: const; and typedef;
Edit: #AndreyT points out it is not a standard defined behavior. For the full answer, I would like to know about any possible advantages that arose in front of GCC devs when they decided this type of code should be compilable.
This looks like a degenerate form of declaration.
In C declaration is not a statement. It is a declaration. And what you have above is not allowed.
6.7 Declarations
2 A declaration shall declare at least a declarator (other than the
parameters of a function or the members of a structure or union), a
tag, or the members of an enumeration.
In C++ declaration is a statement. But still what you have above is not allowed. From C++03
7 Declarations
3 In a simple-declaration, the optional init-declarator-list can be
omitted only when declaring a class (clause 9) or enumeration (7.2),
that is, when the decl-specifier-seq contains either a
class-specifier, an elaborated type-specifier with a class-key (9.1),
or an enum-specifier.
If some compiler allows this in C or C++ code, it must be a quirk of that compiler. You should direct that question to its authors.
As you probably know, the syntax of C and C++ is not specified by the grammar alone. Doing it by the grammar alone would be too complicated or downright impossible. Some additional restrictions are imposed by the text that accompanies the grammar. Compilers usually treat the grammar itself with respect, but when it comes to those elaborate additional restrictions... many compilers allows some violations to slip through.
I would make an educated guess that this must be a side-effect of the "empty declaration" extension. Since the beginning of times empty declarations were illegal in C and C++. For example, this code has always been illegal
void foo() {}; // In file scope
because it follows function definition with an empty declaration. However, virtually all compilers accepted it, allowing empty declarations as an extension. For the very same reason you could write
;;;; // In file scope
in the middle of the file and have your code compile. What you have in your example is also an empty declaration, into which you added some inconsequential qualifiers and storage-class specifiers.
P.S. Correct me if I'm wrong, but C++11 legalized empty declarations. I'm not sure about C11.

Static Constant Class Members

Consider the following snippet:
struct Foo
{
static const T value = 123; //Where T is some POD-type
};
const T Foo::value; //Is this required?
In this case, does the standard require us to explicitly declare value in a translation unit? It seems I have conflicting information; boost and things like numeric_limits from the STL seem to do this sort of thing just like in my snippet.
OTOH, I remember reading somewhere (albeit a long long time ago) that you're still required to provide a declaration in a translation unit.
If this is the case, what about template specialization? Will each specialization require a declaration?
I'd appreciate your comments as to what the "right way" is.
You have to provide a definition in a translation unit too, in case you use the value variable. That means, if for example you read its value.
The important thing is that the compiler is not required to give a warning or error if you violate that rule. The Standard says "no diagnostic required" for a violation.
In the next C++ Standard version, the rule changed. A variable is not used when it is used as a constant expression. Simply reading value above where the variable is initialized directly in the class means that still no definition is required then.
See the definition of use in section 3.2 One Definition Rule of the Standard and requirement for a definition for static data-members in 9.4.2, paragraph 4 and 5 (in the C++98 Standard. Appears in paragraph 3 and 4 in the n2800 draft of the next Standard).
Correction: The rule already changed for c++03: If the variable appears where a integral constant expression is required, no definition is needed (quoting from an unofficial revisions list for the 2003 update), see resolution for this language defect report:
An expression is potentially evaluated unless it appears where an integral constant expression is required (see 5.19), is the operand of the sizeof operator (5.3.3), or is the operand of the typeid operator and the expression does not designate an lvalue of polymorphic class type (5.2.8)...
Note that even then, many uses are in cases where an integral constant is not required. Cases where one is, is in array dimensions or in template metaprogramming. So strictly speaking (see this report), only the c++1x solution provides really guarantee that in obvious cases also like "s == string::npos" where an integral constant is not required the definition of the static member is not needed, because the next Standard has a different, better wording of 3.2. This is however quite theoretical stuff, since most (all?) compiler don't moan anyway. Thanks for the guy in the comment section for telling me.
To add on to what litb said, from my copy of n2798:
9.4.2
[...]
2 The declaration of a static data member in its class definition is not a definition and
may be of an incomplete type other than cv-qualified void. The definition for a static
data member shall appear in a namespace scope enclosing the member’s class definition. In
the definition at namespace scope, the name of the static data member shall be qualified
by its class name using the :: operator.
You don't have to provide a definition for static integral constant members if you don't use them in some way that requires them to be stored in memory somewhere (e.g. take the address of such a member). See Stroustrup's The C++ Programming Language, section 10.4.6.2.
Edit:
Oops, I just re-read the question, and the question was for some type T. In general you would need to provide a definition, I agree. But if you used something from the int family, you wouldn't necessarily have to (with the caveat above).