Compiler error when using CRTP with static_assert

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 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 static_assert , and complains that

 error: no member named 'x_derived' in 'Derived' static constexpr int x_base = Derived::x_derived; 

Which compiler is right (if any)? Is there a good way to fix the code?

+6
source share
1 answer

Access to nested names requires the class to be complete, but Derived is not yet complete:

 template<typename Derived> struct Base { static constexpr int x_base = Derived::x_derived; ^^^^^^^^^ }; 

therefore, the code is poorly formed.

There are several workarounds. First, you can separately pass the value as an argument to the template:

 template <typename Derived, int x_derived> struct Base { static constexpr int x_base = x_derived; }; struct Derived : public Base<Derived, 5> { }; 

Secondly, if possible (for example, you do not need x_derived declare any elements), you can move the value to a function to delay its creation:

 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; }; 
+9
source

All Articles