Consider the following code:
template<typename Derived>
struct Base {
static constexpr int x_base = Derived::x_derived;
//static_assert(x_base > 1, "Oops");
};
struct Derived : public Base<Derived> {
static constexpr int x_derived = 5 ;
};
Base<Derived> obj;
This compiles fine on gcc but if I uncomment the static_assert
line, it complains that
error: incomplete type 'Derived' used in nested name specifier
static constexpr int x_base = Derived::x_derived;
I tried it with different versions of gcc from 4.9 to 5.3 and I get the same error (you can try it on godbolt here). clang refuses to compile it even without the static_assert
, and complains that
error: no member named 'x_derived' in 'Derived'
static constexpr int x_base = Derived::x_derived;
Which compiler is correct (if any)? Is there a nice way to fix the code?
Accessing nested names requires the class to be complete, but Derived
isn't complete here yet:
template<typename Derived>
struct Base {
static constexpr int x_base = Derived::x_derived;
^^^^^^^^^
};
so the code is ill-formed.
There are a few workarounds. First, you can separately just pass in the value as a template argument:
template <typename Derived, int x_derived>
struct Base {
static constexpr int x_base = x_derived;
};
struct Derived : public Base<Derived, 5> { };
Second, if possible (e.g. you don't need x_derived
to declare any members), you can move the value into a function to delay its instantiation:
template<typename Derived>
struct Base {
static constexpr int x_base() {
static_assert(Derived::x_derived > 1, "Oops");
return Derived::x_derived;
}
};
struct Derived : public Base<Derived> {
static constexpr int x_derived = 5;
};
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