I am trying to write a CRTP to contain a static constexpr
of the derived type, since this is impossible to do with just one class. This code compiles fine in GCC, but clang complains that Derived
is an incomplete type. Which one is right?
template<class T>
class Base {
public:
static constexpr T a = T(1), b = T(20);
};
class Derived : public Base<Derived> {
public:
int x;
constexpr Derived(int x) : x(x) {}
};
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With