Derived
is incomplete at the point at which Base<Derived>
is instantiated ([class.mem]/2), which happens right at definition time. You used constexpr
, which necessitates an initializer as per [class.static.data]/3, and when Base<Derived>
is instantiated, so are the declarations of its static data members ([temp.inst]/3), which includes initializers. However, the initializers are attempting to create an object of incomplete type, which is ill-formed.
You can declare your member as const
instead:
template<class T>
class Base {
public:
static const T a;
};
template <typename T>
constexpr T Base<T>::a = T(1);
since the initializer is now at the definition, the instantiation of this initializer can be deferred until e.g. Derived
is complete. Demo with Clang.
Note that Clang doesn't yet treat a
as constexpr
because it fails to eagerly instantiate its definition. See bug #24541.