Reputation: 517
An example:
class Base
{
protected:
virtual void function() { std::cout << "Base\n"; }
void callfunction(void (Base::* func)()) { (this->*func)(); }
};
class Derived1 : public Base
{
public:
void publicCall() { callfunction(&Derived1::function); }
private:
void function() override { std::cout << "Derived1\n"; }
};
I would like to be able to send the derived function pointer to the base class to fulfill a pattern that can be specified in the base class. Thus, reusing code.
However, I'm not sure what the type is supposed to be in the base class since Base::* is not a Derived1::*.
I get the following error:
No instance of overloaded function callfunction matches the argument list: arguments types are (Derived1::*)
Now obviously, I could change the data type to be Derived1::*
, but that wouldn't allow me to send in other derived class virtual functions back to Base
to handle, such as Derived2::function()
Can a template sort of function be created like this?
Upvotes: 3
Views: 450
Reputation:
Use std::function<>
instead of C
style function pointer.
std::function<returnType (parameterType)> functionPointer = functionName;
Do not forget to include <functional>
.
I think this will resolve your problem, but for sure it is preferred.
To pass it directly:
void callfunciton(const std::function<void()>& func);
and call by
callfunction([]{ function(); });
EDIT:
Read this to learn why you should use std::function<>
.
Upvotes: 2
Reputation: 119877
Just send &Base::function
. Since it's virtual, the right one will be called.
The only problem here is that Base::function
is protected and you cannot access it from Derived
(strange but true). OTOH &Derived::function
won't convert to void (Base::* func)()
(and for a good reason). So you have to either make Base::function
public, or provide an accessor:
class Base {
...
protected:
auto getFunction() { return &Base::function; }
Upvotes: 2
Reputation: 25327
You can cast the member function pointer to the base class member function pointer type: callfunction(static_cast<void (Base::*)()>(&Derived1::function));
. Full example:
class Base
{
protected:
virtual void function() { std::cout << "Base\n"; }
void callfunction(void (Base::* func)()) { (this->*func)(); }
};
class Derived1 : public Base
{
public:
void publicCall() { callfunction(static_cast<void (Base::*)()>(&Derived1::function)); }
private:
void function() override { std::cout << "Derived1\n"; }
};
This is allowed; see cppreference on pointers to member functions:
Pointer to member function of a base class can be implicitly converted to pointer to the same member function of a derived class ...
Conversion in the opposite direction, from a pointer to member function of a derived class to a pointer to member function of an unambiguous non-virtual base class, is allowed withstatic_cast
and explicit cast
In this case, we are converting derived to base rather than vice-versa, so we need to static_cast
.
You can avoid requiring the cast from the call-site by casting in Base
from a template:
class Base
{
protected:
virtual void function() { std::cout << "Base\n"; }
void callfunction(void (Base::* func)()) { (this->*func)(); }
template <typename Derived, std::enable_if_t<std::is_convertible_v<Derived const*, Base const*>, int> = 0>
void callfunction(void (Derived::* func)()) { callfunction(static_cast<void (Base::*)()>(func)); }
};
class Derived1 : public Base
{
public:
void publicCall() { callfunction(&Derived1::function); }
private:
void function() override { std::cout << "Derived1\n"; }
};
Compiler Explorer link: https://godbolt.org/z/3x8qPK4Tf
Upvotes: 1
Reputation: 68
I think that a template function should work
template<class _DType>
void Base::callFunction(void(_DType::*func)()) { func(); }
then the function from Derived1
void Derived1::publicCall() { Base::callFunction(&Derived1::function); }
This work as long as Derived1
is derived by Base
, that is not what you wrote but I'm assuming you just missed, anyway next time I would add class Derived1: public Base
to have a more clear code.
Upvotes: 1
Reputation: 6131
Your question is asking for CRTP, a poorly named but well known label for the idiom described in a 1995 article by Jim Coplien, titled "A Curiously Recurring Template Pattern". The idea is well documented, so I won't go into depth, but the idea is pretty simple: The base class takes a template argument, and the derived class provides its type to the base. Then the base class can "downcast" the this pointer to the derived type and call the function without needing a virtual call.
https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
What is the curiously recurring template pattern (CRTP)?
Upvotes: 1