This is a common problem when using CRTP: Base<Derived>
is instantiated at the point where it is encountered in Derived
's list of bases, at which time Derived
is not yet a complete type since the rest of its declaration hasn't been parsed yet. There are various workarounds. For static_assert
, you need to delay instantiation of the assertion until Derived
is complete. One way to do so is to put the assertion in a member function of Base
that you know must be instantiated - the destructor is always a good choice (Live at Coliru):
template <class T>
class Base
{
public:
~Base() {
static_assert(std::is_same<decltype(T::foo(1)), int>::value, "ERROR STRING");
}
};
class Derived : public Base<Derived>
{
public:
static int foo(int) { return 42; };
};
Addressing question #2: C::*
is the syntax for "pointer to member of class C
." So int(*)(int)
is "pointer to function taking a single int
parameter and returning int
", and int(C::*)(int)
is analogously "pointer to member function of C
taking a single int
parameter and returning int
." The monstrosity
typename C::const_iterator(C::*)() const
would translate to "pointer to constant member function of C
taking no parameters and returning C::const_iterator
" where of course the typename
is necessary to indicate that the dependent name C::const_iterator
is a type.