Consider the following standard CRTP example:
#include <iostream>
template<class Derived>
struct Base {
void f() { static_cast<Derived *>(this)->f(); }
void g() { static_cast<Derived *>(this)->g(); }
};
struct Foo : public Base<Foo> {
void f() { std::cout << 42 << std::endl; }
};
int main() {
Foo foo;
foo.f(); // just OK
foo.g(); // this will stack overflow and segfault
}
If this was regular virtual inheritance I could have mark virtual f
and g
methods as pure like
struct Base {
virtual void f() = 0;
virtual void g() = 0;
};
and get a compile time error about Foo
being abstract. But CRTP offers no such protection. Can I implement it somehow? Runtime check is acceptable too. I thought about comparing this->f
pointer with static_cast<Derived *>(this)->f
, but didn't manage to make it work.
Here is another possibility:
#include <iostream>
template<class Derived>
struct Base {
auto f() { return static_cast<Derived *>(this)->f(); }
auto g() { return static_cast<Derived *>(this)->g(); }
};
struct Foo : public Base<Foo> {
void f() { std::cout << 42 << std::endl; }
};
int main() {
Foo foo;
foo.f(); // just OK
foo.g(); // this will not compile
}
For GCC, it gives a pretty clear error message ("error: use of 'auto Base::g() [with Derived = Foo]' before deduction of 'auto'"), while for Clang, it gives a slightly less readable infinitely recursing template instantiation of Base<Foo>::g
, with g
instantiating itself but eventually ending in an error.