GOAL:
I would like to achieve type-safe dynamic polymorphism (i.e. run-time dispatch of a function call) on unrelated types
I once solved this by simulating .NET delegates:
template
class Delegate
{
//static_assert(false, "T must be a function type");
};
template
class Delegate
{
private:
class HelperBase
{
public:
HelperBase()
{
}
virtual ~HelperBase()
{
}
virtual ReturnType operator()() const = 0;
virtual bool operator==(const HelperBase& hb) const = 0;
virtual HelperBase* Clone() const = 0;
};
template
class Helper : public HelperBase
{
private:
Class* m_pObject;
ReturnType(Class::*m_pMethod)();
public:
Helper(Class* pObject, ReturnType(Class::*pMethod)()) : m_pObject(pObject), m_pMethod(pMethod)
{
}
virtual ~Helper()
{
}
virtual ReturnType operator()() const
{
return (m_pObject->*m_pMethod)();
}
virtual bool operator==(const HelperBase& hb) const
{
const Helper& h = static_cast(hb);
return m_pObject == h.m_pObject && m_pMethod == h.m_pMethod;
}
virtual HelperBase* Clone() const
{
return new Helper(*this);
}
};
HelperBase* m_pHelperBase;
public:
template
Delegate(Class* pObject, ReturnType(Class::*pMethod)())
{
m_pHelperBase = new Helper(pObject, pMethod);
}
Delegate(const Delegate& d)
{
m_pHelperBase = d.m_pHelperBase->Clone();
}
Delegate(Delegate&& d)
{
m_pHelperBase = d.m_pHelperBase;
d.m_pHelperBase = nullptr;
}
~Delegate()
{
delete m_pHelperBase;
}
Delegate& operator=(const Delegate& d)
{
if (this != &d)
{
delete m_pHelperBase;
m_pHelperBase = d.m_pHelperBase->Clone();
}
return *this;
}
Delegate& operator=(Delegate&& d)
{
if (this != &d)
{
delete m_pHelperBase;
m_pHelperBase = d.m_pHelperBase;
d.m_pHelperBase = nullptr;
}
return *this;
}
ReturnType operator()() const
{
(*m_pHelperBase)();
}
bool operator==(const Delegate& d) const
{
return *m_pHelperBase == *d.m_pHelperBase;
}
bool operator!=(const Delegate& d) const
{
return !(*this == d);
}
};
You can use it much like .NET delegates:
class A
{
public:
void M() { ... }
};
class B
{
public:
void M() { ... }
};
A a;
B b;
Delegate d = Delegate(&a, &A::M);
d(); // calls A::M
d = Delegate(&b, &B::M);
d(); // calls B::M
This works with methods that have no arguments. If you can use C++11, you can modify it to use variadic templates to handle any number of parameters. Without C++11, you need to add more Delegate specializations to handle specific numbers of parameters:
template
class Delegate
{
...
};
template
class Delegate
{
...
};
With this Delegate class you can also emulate .NET events, which are based on delegates.