我会尽可能简单地描述我的问题。
我的问题是什么:
我将frist课作为单身人士:
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;
};
这是第二课,我希望有可能从setChannelA
类调用CTimer1
方法作为setPwm
类的CServo
方法:
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
};
以下是registerPwmTimer
方法:
void CServo::registerPwmTimer(void (*callback)(uint8_t u8_buffer))
{
setPwm = callback;
}
然后我尝试将指针指定为以下方法:
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)
{
}
}
我有错误:
error: no matching function for call to 'CServo::registerPwmTimer(<unresolved overloaded function type>)'
重要的是:
我无法使用std::function
因为这是C ++中嵌入式设备代码的一部分,所以我需要节省内存消耗。有什么方法可以达到这个效果吗?如果有一种可能性,那么请使用一些标准库来获取答案。谢谢你的帮助。
答案 0 :(得分:1)
您的问题是函数指针必须指向静态函数。当您调用实例函数(方法)时,会有一个隐藏的第一个参数,该参数是调用该函数的对象。 (此隐藏参数在函数定义中以this
形式提供。)
您的CServo::registerPwmTimer()
函数签名与调用成员函数完全不兼容;单独的函数指针不提供将参数绑定到指针的方法,因此即使您可以使用(自由)函数指针类型传递成员函数指针,也无法在函数时确定隐藏的this
参数指针被调用。
换句话说,它会失败的原因与尝试CTimer1::setChannelA(0)
失败的原因相同 - 你想要调用那个方法,但你还没有传达哪个对象可以调用它。
更改CServo::registerPwmTimer
的签名以接受std::function
对象而不是原始函数指针。 std::function
对象可以从函数指针构造,但它们也可以用lambda构造,一些标准库函数返回函数对象:
void registerPwmTimer(std::function<void(uint8_t)>);
现在,您可以使用std::bind
创建一个将对象实例绑定到成员函数指针的新函数:
servo1.registerPwmTimer(std::bind(&CTimer1::setChannelA, timer1));
请注意,std::bind
不会延长timer1
指向的对象的生命周期。如果在该对象被销毁之后调用返回的函数,则结果是未定义的行为。
另一种选择是接受实例和指向成员函数的指针。这种方法的问题是需要使用模板:
template <typename T>
void registerPwmTimer(void (T::*)(uint8_t), T&);
这本身并不错,但你最后要做的是创建一个多态包装类,这样你就可以将它插入你的回调列表以及不共享同一个T
的其他回调。那时,你只是在重新创建std::function
,因为std::function
已经成为围绕可调用事物的多态包装的目的。
为了说明自己实现多态可调用包装器的混乱,这是一个非常轻松的例子。我将展示一组这些类型的声明,并链接到一个示例实现。
这是基本类型,其中纯虚拟operator()
用作调用操作。
class poly_callable
{
public:
virtual void operator()(int) const = 0;
};
现在我们有一个函数指针类型(也适用于指向仿函数的指针):
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;
};
一个用于成员函数 - 哦,但const
成员函数和非const
成员函数不可互换,因此我们需要一个额外的模板参数:
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;
};
另外,我们需要一些辅助函数来允许编译器推断出模板类型。一个用于函数指针:
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));
}
两个用于成员函数(const
和非 - 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));
}
如果你想看到这一切,我做了一个"simple" and working example。
所以...只需使用std::function
。 没有理由重新发明这些东西。