Я с удивлением обнаружил, что GCC и Clang не согласны с тем, чтобы дать мне ошибку компоновщика при передаче статического члена constexpr по значению, если нет определения вне класса:
#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);
}
Фрагмент можно воспроизвести с помощью здесь.
Я хотел бы использовать синтаксис первой строки без определения вне класса:
static constexpr struct E {} nested {}; // works in gcc and clang
Если в E
нет членов, Clang и GCC, похоже, не заботятся о том, чтобы у меня не было определения класса nested
, если я отключу ODR (например, взяв адрес). Является ли этот стандарт обязательным или удачным?
Когда есть члены, GCC (5.2), похоже, дополнительно хочет, чтобы я вручную определил конструктор экземпляра constexpr. Является ли это ошибкой?
От googling и SO я нашел несколько разных ответов, но трудно разоблачать, которые обновлены с С++ 14. В С++ 98/03 я считаю, что внутри класса могут быть инициализированы только целые типы. Я думаю, что С++ 14 расширил это до "литерала", который включает в себя Constexpr конструктивные вещи. Я не знаю, если это то же самое, что сказать, что мне разрешено уйти с отсутствием определения вне класса.