I will describe my problem the simplest as I can.
What is my issue:
I have frist class as a singleton:
class CTimer1
{
public:
static CTimer1 * getInstance(); //This gives me pointer to instance
void setChannelA(uint8_t compareValue);
private:
//Cnstructors
CTimer1(); //Prevent consttuction but allow in getInstance
CTimer1(const CTimer1&); //Prevent construction by copying
CTimer1& operator=(const CTimer1&); //Prevent assigment
~CTimer1(); //Prevent unwanted destruction
static CTimer1 * timerInstance;
static bool isCreated;
};
And here is second class where I would like to have possibility to call setChannelA
method from CTimer1
class as a setPwm
method from CServo
class:
class CServo {
public:
CServo();
~CServo();
public:
//public methods
void registerPwmTimer(void (*callback)(uint8_t u8_buffer));
void (*setPwm)(uint8_t u8_buffer); //As this method I would like to call setChannelA from CTimer1 class
};
Here is registerPwmTimer
method:
void CServo::registerPwmTimer(void (*callback)(uint8_t u8_buffer))
{
setPwm = callback;
}
Then I have tried to assign pointer to this method as a following:
int main()
{
CTimer1 * timer1 = CTimer1::getInstance();
CServo servo1();
servo1.registerPwmTimer(timer1->setChannelA);
servo1.setPwm(10); //This is example how I want to call setChannelA method
while(1)
{
}
}
I have error:
error: no matching function for call to 'CServo::registerPwmTimer(<unresolved overloaded function type>)'
What is important:
I can't use std::function
because this is some part of code in C++ for embedded device, so I need to save memory consumption. Is there any way that I will be able to achieve this effect? If ony one possibility to do this is ot use some std library please for answers too. Thanks for your help.
Your problem is that a function pointer necessarily has to point to a static function. When you invoke an instance function (a method) there is a hidden first argument, which is the object on which the function was invoked. (This hidden argument is available as this
within the function's definition.)
Your CServo::registerPwmTimer()
function signature is simply incompatible with invocation of a member function; function pointers alone do not provide a way to bind an argument to the pointer, so even if you could convey the member function pointer using a (free) function pointer type, the hidden this
argument could not be determined when the function pointer was invoked.
To put it another way, it would fail for the same reason that trying CTimer1::setChannelA(0)
would fail -- you want to invoke that method, but you haven't communicated which object on which to invoke it.
Change the signature of CServo::registerPwmTimer
to accept an std::function
object instead of a raw function pointer. std::function
objects can be constructed from function pointers, but they can also be constructed from lambdas, and some standard library functions return function objects:
void registerPwmTimer(std::function<void(uint8_t)>);
Now, you can use std::bind
to create a new function that binds the object instance to the member function pointer:
servo1.registerPwmTimer(std::bind(&CTimer1::setChannelA, timer1));
Note that std::bind
does not extend the lifetime of the object pointed to by timer1
. If the returned function is invoked after that object is destructed, the result is undefined behavior.
Another alternative would be to accept both an instance and a pointer to a member function. The problem with this approach is it requires using templates:
template <typename T>
void registerPwmTimer(void (T::*)(uint8_t), T&);
This isn't bad in itself, but what you'll wind up doing is creating a polymorphic wrapper class so that you can insert this into your callback list alongside other callbacks that don't share the same T
. At that point, you're just recreating std::function
, since std::function
already serves the purpose of being a polymorphic wrapper around callable things.
To illustrate the mess of implementing a polymorphic callable wrapper yourself, here is a very light example. I will show the declarations of a set of these types, and link to an example implementation.
This is the base type, with a pure virtual operator()
that serves as the invocation operation.
class poly_callable
{
public:
virtual void operator()(int) const = 0;
};
Now we have a type for function pointers (also works with pointer-to-functor):
template <typename T>
class fn_poly_callable : public poly_callable
{
public:
typedef T fn_type;
fn_poly_callable(T);
virtual void operator()(int) const;
private:
T fn;
};
And one for member functions -- oh, but const
member functions and non-const
member functions are not interchangeable, so we need an extra template parameter for that:
template <typename T, typename M = void (T::*)(int)>
class member_poly_callable : public poly_callable
{
public:
typedef T object_type;
typedef M member_fn_type;
member_poly_callable(member_fn_type, object_type&);
virtual void operator()(int) const;
private:
member_fn_type mfn;
object_type& target;
};
Plus we'll want some helper functions to allow the compiler to infer the template types. One for function pointers:
template <typename T>
std::unique_ptr<poly_callable> make_poly_callable(T fn)
{
return std::unique_ptr<poly_callable>(new fn_poly_callable<T>(fn));
}
Two for member functions (const
and non-const
):
template <typename T>
std::unique_ptr<poly_callable> make_poly_callable(void (T::*mfn)(int), T& target)
{
return std::unique_ptr<poly_callable>(new member_poly_callable<T>(mfn, target));
}
template <typename T>
std::unique_ptr<poly_callable> make_poly_callable(void (T::*mfn)(int) const, T& target)
{
return std::unique_ptr<poly_callable>(new member_poly_callable<T, void (T::*)(int) const>(mfn, target));
}
If you want to see it all in action, I made a "simple" and working example.
So... just use std::function
. There's no reason to reinvent this stuff.