C ++将函数作为参数传递给多态类型

时间:2014-02-02 16:57:43

标签: c++ polymorphism

我有功能

void addOnHover(std::function<void(Button&, HoverState)>& func);
void addOnHover(void(*fptr)(Button&, HoverState));

Button继承ButtonBase,这是接口类,我想传递

void hoverOver(game::ButtonBase& button, game::HoverState state)
{
    static int i = 0;
    if (state == game::HoverState::STATE_ENTER)
        std::cout << "entered " <<    button.getLabel().getText().getString().toAnsiString() << " " << ++i << "\n";
    else if (state == game::HoverState::STATE_LEAVE)
        std::cout << "left " << button.getLabel().getText().getString().toAnsiString() << " " << ++i << "\n";
    else
        std::cout << "inside " << button.getLabel().getText().getString().toAnsiString() << " " << ++i << "\n";
}

我们可以说b的类型为Button

但如果我b.addOnHover(hoverOver);它将无法编译(一些时髦的编译器错误,就像这种工作人员一样)。

如果我执行b.addOnHover(std::function<void(game::Button&, game::HoverState)>(hoverOver);或者我将hoverOver从game::ButtonBase&更改为game::Button&,我可以使其工作,但我想知道是否可以在没有这种冗长的情况下完成(标准: :function ...)并将参数保持为game::ButtonBase&,因为将来可能会有更多的Button类

根据Bolov请求,传递hoverOver

时出现编译错误
1>Source.cpp(58): error C2664: 'void game::Button::addOnHover(std::function<_Fty> &)' : cannot convert parameter 1 from 'void (__cdecl *)(game::ButtonBase &,game::HoverState)' to 'std::function<_Fty> &'
1>          with
1>          [
1>              _Fty=void (game::Button &,game::HoverState)
1>          ]

编辑:

一种可能的解决方案,即使仍然非常冗长就是添加

template <class T, class C, class Q>
std::function<void(T&, C)> wrap(Q ptr)
{
    return std::function<void(T&, C)>(ptr);
}

并致电b.addOnHover(game::wrap<game::Button, game::HoverState>(hoverOver);,但我不确定它是否能正常运作

2 个答案:

答案 0 :(得分:2)

你遇到的一个问题是非const左值引用不能绑定到右值。

void addOnHover(const std::function<void(Button&, HoverState)>& func);

或(最好):

void addOnHover(std::function<void(Button&, HoverState)> func);

对于你的版本,参数func是一个非常量左值,当你调用它时,b.addOnHover(hoverOver) hoverOver是一个指向函数的指针,因此创建了一个类型的临时对象std::func(rvalue),正如我所说,不能绑定到非const左值引用。

顺便说一下,当我看到错误信息时,我发现了这一点,因此尝试解决错误非常重要。

答案 1 :(得分:2)

我可以看到两个潜在的问题。

1)'参数'的类型(即按钮)  void addOnHover(std::function<void(Button&, HoverState)>& func);   比您给出的值更具体   ButtonBase

中的void hoverOver(game::ButtonBase& button, game::HoverState state)...

这就好像您要将父类的ptr分配给子类的ptr。

如果您使用了普通值,则ButtonBase&参数应该接受Button&,但不是相反。换句话说,我认为你应该

void addOnHover(std::function<void(ButtonBase&, HoverState)>& func);

void hoverOver(game::Button& button, game::HoverState state)...  (或void hoverOver(game::ButtonBase& button, game::HoverState state)...

2)即使类型匹配,std::function也不会自动接受来自相同类型的函数指针或lambda的转换。现在在c ++ 11中使用std::function是一件痛苦的事。您需要首先将函数分配给std::function对象,或者像您一样调用构造函数。不幸的是,这与您可以std::string接受const char*的情况不同。

我猜你的std::function用法或包装器做的是类型转换。所以编译器接受它是因为你明确告诉编译器演员应该没问题。这并不意味着类型实际上是兼容的。

关于第二个问题,我提出了一个相关的问题,关于如何让std::function接受相应类型的函数(plain,lambda等):How to make C++11 functions taking function<> parameters accept lambdas automatically。我得到的答案最多的是我不应该使用std::function或期望以这种方式使用它。