Following techniques from ‘Modern C++ Design’, I am implementing a persistence library with various compile-time optimisations. I would like the ability to dispatch a function to a templated member variable if that variable derives from a given class:
template<class T, template <class> class Manager = DefaultManager> class Data { private: T *data_; public: void Dispatch() { if(SUPERSUBCLASS(Container, T)) { data_->IKnowThisIsHere(); } else { Manager<T>::SomeGenericFunction(data_); } } }
Where SUPERSUBCLASS is a compile-time macro to determine object inheritance. Of course, this fails in all cases where T does to inherit from Container (or T is an intrinsic type etc etc) because the compiler rightly complains that IKnowThisIsHere() is not a data member, even though this code path will never be followed, as shown here after preprocessing with T = int:
private: int *data_; public: void Dispatch() { if(false) { data_->IKnowThisIsHere();
Compiler clearly complains at this code, even though it will never get executed. A suggestion of using a dynamic_cast also does not work, as again a type conversion is attempted at compile time that is not possible (for example with T=double, std::string):
void Dispatch() { if(false) { dynamic_cast<Container*>(data_)->IKnowThisIsHere(); error: cannot dynamic_cast '((const Data<double, DefaultManager>*)this)->Data<double, DefaultManager>::data_' (of type 'double* const') to type 'class Container*' (source is not a pointer to class) error: cannot dynamic_cast '((const Data<std::string, DefaultManager>*)this)->Da<sttad::string, DefaultManager>::data_' (of type 'struct std::string* const') to type 'class Container*' (source type is not polymorphic)
I really need to emulate (or indeed persuade!) having the compiler emit one set of code if T does inherit from Container, and another if it does not.
Any suggestions?
Overloading can be useful to implement compile-time dispatching, as proposed by Alexandrescu in his book ‘Modern C++ Design’.
You can use a class like this to transform at compile time a boolean or integer into a type:
The following source code shows a possible application:
Of course what really makes the job is the MACRO() or a better implementation as a metafunction