I was surprised to find that GCC and Clang disagree on whether to give me a linker error when passing a static constexpr member by value when there is no out-of-class definition:
#include <iostream>
#include <type_traits>
#include <typeinfo>
template <typename X>
void show(X)
{
std::cout << typeid(X).name() << std::endl;
}
template <typename T>
struct Foo
{
//static constexpr struct E {} nested {}; // works in gcc and clang
//static constexpr struct E {T x;} nested {}; // doesn't work in gcc
//static constexpr enum E {} nested {}; // works in gcc and clang
//static constexpr enum E { FOO } nested {}; // works in gcc and clang
//static constexpr struct E { constexpr E() {} constexpr E(const E&) {} T x=T();} nested {}; // works in gcc and clang
static constexpr struct E { constexpr E() {} constexpr E(const E&) = default; T x=T(); } nested {}; // doesn't work in gcc
};
int main()
{
Foo<int> x;
show(x.nested);
}
Snippet can be played with here.
I would like to use the first line's syntax with no out-of-class definition:
static constexpr struct E {} nested {}; // works in gcc and clang
When there are no members in E
, Clang and GCC only seem to care that I have no out-of-class definition of nested
if I trip ODR (e.g. by taking the address). Is this standard mandated or luck?
When there are members, GCC (5.2) appears to additionally want me to have manually defined a constexpr copy constructor. Is this a bug?
From googling and SO I have found several different answers but it's hard to tease apart which are up to date with C++14. In C++98/03 I believe only integer types could be initialized inside the class. I think that C++14 expanded this to 'literal' types which includes constexpr constructable things. I don't know if this is the same as saying I am allowed to get away with not having an out-of-class definition though.