我有功能
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);
,但我不确定它是否能正常运作
答案 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
或期望以这种方式使用它。