Reputation: 12116
I've been using the Curiously recurring template pattern The general code looks like this:
template <typename T> void genericFunction(T &);
template <typename T> struct Functionality {
void genericMethod() {
genericFunction(*((T *)this)) ;
}
};
struct Klass : public Functionality<Klass> {};
void main() {
Klass obj ;
obj.genericMethod();
}
template <> void genericFunction<Klass>(Klass &obj) {
//do stuff with Klass &obj here
}
I ran into an error today which cost me about 90 minutes of hair-pulling fustration, this error was caused by using an incorrect template parameter for my base class inheritance declaration, somewhat like so:
struct Klass : public Functionality<SomeOtherKlass> {}; //SomeOtherKlass wrong!!!
I'd like to enhance my code so that this mismatch between the derived class and the base class template parameter is detected (runtime, compile time, anytime :) ), is this even possible?, thanks.
Upvotes: 7
Views: 630
Reputation: 98964
You could assert the relation in e.g. genericMethod()
using Boost or C++11 features:
BOOST_STATIC_ASSERT(( boost::is_base_of<Functionality<T>, T>::value ));
... although that is assuming that the other class doesn't derive from Functionality<T>
as well.
An alternative could be to assert the relation at runtime in test-builds:
template <typename T> struct Functionality {
#ifdef TEST_BUILD
virtual ~Functionality() {}
#endif
void genericMethod() {
#ifdef TEST_BUILD
assert(dynamic_cast<T*>(this));
#endif
genericFunction(*((T *)this)) ;
}
};
Note that the test won't work inside constructors and destructors
Upvotes: 3
Reputation: 19721
In C++11, the following should work:
template<typename T> class Base
{
friend T; // allowed in C++11
private:
~Base() {}
public:
// ...
};
class Derived: public Base<Derived> {}; // OK
class WronglyDerived: public Base<Derived> {}; // Error: destructor of base class is private
Upvotes: 2
Reputation: 12116
The most tangible suggestion thus far is to use dynamic_cast to expose malformed inheritance declarations in the Base class constructor, like so:
#include <iostream>
template <typename T> struct Base {
Base() {
std::cout<<dynamic_cast<T *> (this)<<std::endl;
}
virtual void iampolymorphic(){}
};
struct Decoy {} ;
struct Pass : public Base<Pass>{}; //correct
struct Fail : public Base<Decoy>{}; //incorrect
int main() {
Pass p ;
Fail f ;
return 1 ;
}
This code compiles on g++ 4.6.1, Amd64 Xubuntu 11.10. The output for both dynamic cast operations is a null pointer. Comments, criticisms and observations are welcomed.
Upvotes: -1
Reputation: 18954
Suppose you add a templated constructor to the base that takes a pointer to arbitrary type;
template<class U> Functionality(U *) { ... }
Then each derived class's constructor can pass its this pointer to the constructor, and in the body of the constructor you just static assert that U and T are the same type.
The constructor parameter is never actually used so should be optimised out entirely. And if this is the only base class constructor you can't forget to call it. The only problem would be if you passed something other than this.
Upvotes: 0
Reputation: 18954
You could use a dynamic_cast, which will return null if you have the wrong parameter type. (You'll need at least one virtual function in the base for this to work - the destructor, say.)
If you're worried about efficiency, boost has a polymorphic_cast which does a dynamic cast in debug mode but a static cast for production.
(And in any case it would be nice to avoid the use of the C-style cast.)
Upvotes: 1