I'm trying to write a class that accepts a a function pointer AND/OR a functor to be user later by the class. To illustrate better what I'd like to do:
template <typename T> class Holder {
private:
T *m_ptr;
<something> m_func;
public:
Holder(T *ptr) : m_ptr(ptr), m_func(NULL) {
}
Holder(T *ptr, <something> func) : m_ptr(ptr), m_func(func) {
}
~Holder() {
if (m_func) {
m_func(m_ptr);
} else {
delete m_ptr;
}
}
};
Considering I'd like to handler objects of this type:
class MyClass {
public:
void describe() {
cout << "Bla bla bla ...";
}
};
Then I could use it this way:
class MyClassFunctor {
public:
void operator()(MyClass *ptr) const {
cout << "Deleting ptr using functor: ";
ptr->describe();
cout << endl;
delete ptr;
}
};
int main() {
MyClass *myclass = new MyClass();
MyClassFunctor functor();
{
Holder<MyClass> holder(myClass, functor);
}
cout << "I'm out of context now!" << endl;
}
AND (not or) this way:
void myClassDeleter(MyClass *ptr) {
cout << "Deleting ptr using function pointer: ";
ptr->describe();
cout << endl;
delete ptr;
}
int main() {
MyClass *myclass = new MyClass();
{
Holder<MyClass> holder(myClass, &myClassDeleter);
}
cout << "I'm out of context now!" << endl;
}
Notice I'd like to be able to use both approaches: Functors AND function pointers.
I'd say it is possible, since this is what Boost::shared ptr and tr1::shared_ptr does. I tried digging into Boost::shared_ptr code, but I couldn't really understand how they do it.
I'm sorry if my code is wrong or seems to be naive. I tried to explain the problem as concisely as possible, so code correctness wasn't my main focus here (I realize this is important).
Notice I don't even think about rewriting a smart pointer class from scratch. This is out of question here, since I know it is not a wise call. I'm interested in knowing how to do it so I can use this mechanism for other purposes. Smart pointers were simply the simplest use of that I could remember.
For now, I'd like to avoid using boost and C++11. Is it possible to do it using plain c++03?
Thanks very much for your time.
The answer is: Type Erasure.
The implementation is not that simple, and I suggest reading about Type Erasure a little (as I just did!).
First of all, you need to create the Type Erased apparatus:
Then you can declare the Holder class:
Then you can use it passing function pointers, functors, or even nothing:
Here is the output:
Hope it's useful for someone else.