`static constexpr auto` data-member initialized with unnamed enum
auto, c++, c++11, enums, language-lawyer
Solution
Who's to blame?
GCC is inaccurately rejecting your snippet, it is legal according to the C++11 Standard (N3337). Quotations with proof and explanation is located the end of this post.
workaround (A) - add the missing definition
template <class T>
struct foo {
static constexpr auto value = a;
typedef decltype(a) value_type;
};
template<class T>
constexpr typename foo<T>::value_type foo<T>::value;
workaround (B) - use the underlying-type of the enumeration as placeholder
#include <type_traits>
template <class T>
struct foo {
static const std::underlying_type<decltype(a)>::type value = a;
};
What does the Standard say? (N3337)
As stated, the snippet is legal C++11, as can be read in the following quoted sections.
When can we use a type without linkage?
`[basic.link]p8` has detailed wording that describes when a type is "without linkage", and it states that an unnamed enumeration count as such type.
`[basic.link]p8` also explicitly states three contexts where such a type cannot be used, but not one of the contexts apply to our usage, so we are safe.
A type without linkage shall not be used as the type of a variable or function with external linkage unless
- the entity has C language linkage (7.5), or
- the entity is declared within an unnamed namespace (7.3.1), or
- the entity is not odr-used (3.2) or is defined in the same translation unit
Are you sure we can use `auto` in such context?
Yes, and this can be proven by the following quote:
`7.1.6.4p` `auto` specifier `[dcl.spec.auto]`
A `auto` type-specifier can also be used in declaring a variable in the condition of a selection statement (6.4) or an iteration statement (6.5), in the type-specifier-seq in the new-type-id or type-id of a new-expression (5.3.4), in a for-range-declaration, and in declaring a static data member with a brace-or-equal-initializer that appears within the member-specification of a class definition (9.4.2).
Problem
I was working on a C++11 project solely using `clang++-3.4`, and decided to compile using `g++-4.8.2` in case there were any discrepancies in the errors produced. It turned out that g++ rejects some code that clang++ accepts. I have reduced the problem to the MWE given below. ``` enum { a }; template <class T> struct foo { static constexpr auto value = a; }; int main() { static constexpr auto r = foo<int>::value; } ``` foo.cpp:5:23: error: ‘`const<anonymous enum> foo<int>::value`’, declared using anonymous type, is used but never defined [-fpermissive] ``` static const auto value = A; ``` I would like some help answering the following two questions: Which compiler is correct in its interpretation of the standard? I am assuming that one compiler is right in either accepting or rejecting the code, and the other is wrong. How can I work around this issue? I can't name the anonymous enum, because it is from a third-party library (in my case, the enums were `Eigen::RowMajor` and `Eigen::ColMajor`).