Recently I needed to update data in a base class, but only for types derived from that class.
struct Base {
void Func() { cout << "Base::Func calledn"; }
};
struct Child : public Base { };
struct AnotherStruct { };
For example I want to call Base:Func() for all types that have been derived from Base. In the code above this would include Child and Base, but not AnotherStruct. If I've been given AnotherStruct then I don't want to do anything.
void call_base_func( Base* base ) {
base->Func();
}
void call_base_func( void* ) { }
Thanks to function overloading this can be solved easily. Passing a Child to call_base_func will result in the first function being called, while AnotherStruct will use the second function.
But what do we do if Base is using the Curiously Recursive Template pattern?
template
struct Base {
void Func() { cout << "Base::Func calledn"; }
};
struct Child : public Base { };
struct AnotherStruct { };
Well now the type of Base is dependent on the type of Child. This breaks our previous solution as we can't specify Base without also specifying a type. Or can we?
template
void call_base_func( Base* base ) {
base->Func();
}
void call_base_func( void* ) { }
Sure we can. If Base is going to use templates, then so can call_base_func. As an added bonus we also get the type that initially derived from Base.
-
An example of this technique is with smart pointers. More specifically if you have a look a Boost shared_ptr it provides an enable_shared_from_this base class. This class tracks references to the derived object and allows you to acquire a corresponding shared_ptr to that object. The only way this can function is if the shared_ptr class can update the internal data in enable_shared_from_this, and only when the type is derived from enable_shared_from_this.