I was trying to implement static polymorphism using the Curiously Recurring Template Pattern, when I noticed that static_cast<>
, which usually checks at compile time if a type is actually convertible to another, missed a typo in the base class declaration, allowing the code to downcast the base class to one of its siblings:
#include <iostream>
using namespace std;
template< typename T >
struct CRTP
{
void do_it( )
{
static_cast< T& >( *this ).execute( );
}
};
struct A : CRTP< A >
{
void execute( )
{
cout << "A" << endl;
}
};
struct B : CRTP< B >
{
void execute( )
{
cout << "B" << endl;
}
};
struct C : CRTP< A > // it should be CRTP< C >, but typo mistake
{
void execute( )
{
cout << "C" << endl;
}
};
int main( )
{
A a;
a.do_it( );
B b;
b.do_it( );
C c;
c.do_it( );
return 0;
}
Output of the program is:
A
B
A
Why does the cast work with no errors? How can I have a compile time check that could help from this type of errors?
static_cast
to derived classes. You can’t check at compile time what the runtime type will be. – Twicetoldstatic_assert(std::is_base_of<CRTP<decltype(this)>,decltype(this)>::value)
? – Woodcraftcrtp<CRTP> C { ... };
and not need to inherit manually at all. That said, I think metaclasses lends itself more to either combining the desired mixins into a new metaclass or some generalwith_mixins<...> Foo { ... };
– HargreavesA
andC
are derived fromCRTP<A>
, so astatic_cast
is allowed fromCRTP<A>
to either of them. A cast to an unrelated (or ambiguous) type, e.g.B
would require a diagnostic, though. – Epictetus