[英]C++ passing function as argument with polymorphic type
I have functions 我有功能
void addOnHover(std::function<void(Button&, HoverState)>& func);
void addOnHover(void(*fptr)(Button&, HoverState));
Button inherits ButtonBase
, which is interface class and I want to pass 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";
}
lets say b
is of type Button
假设
b
是Button
类型
but if I do b.addOnHover(hoverOver);
但是如果我这样做
b.addOnHover(hoverOver);
it will not compile(some funky compiler error, as always with this kind of staff). 它不会编译(某些时髦的编译器错误,与此类人员一样)。
I can make it work if I do b.addOnHover(std::function<void(game::Button&, game::HoverState)>(hoverOver);
or if I change the hoverOver from taking game::ButtonBase&
to game::Button&
, but I wonder if it could be done without such verbosity(std::function...) and while keeping the argument as game::ButtonBase&
because there may be more Button classes in future 如果我执行
b.addOnHover(std::function<void(game::Button&, game::HoverState)>(hoverOver);
或者将hoverOver从将game::ButtonBase&
更改为game::ButtonBase&
可以使其工作game::Button&
,但是我想知道如果没有这种冗长(std :: function ...)并将参数保留为game::ButtonBase&
,是否可以完成game::ButtonBase&
因为将来可能会有更多的Button类
as per Bolov request, here is compiler error when passing hoverOver
根据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> ]
edit: 编辑:
One possible solution, even tho still pretty verbose is to add 一种可能的解决方案,甚至还很冗长,是添加
template <class T, class C, class Q>
std::function<void(T&, C)> wrap(Q ptr)
{
return std::function<void(T&, C)>(ptr);
}
and call b.addOnHover(game::wrap<game::Button, game::HoverState>(hoverOver);
but Im not sure if it will function correctly yet 并调用
b.addOnHover(game::wrap<game::Button, game::HoverState>(hoverOver);
但我不确定它是否能正常运行
One problem that you have is that an non-const lvalue reference cannot be bound to an rvalue. 您遇到的一个问题是,不能将非常量左值引用绑定到右值。
make 使
void addOnHover(const std::function<void(Button&, HoverState)>& func);
or (preferably): 或(最好):
void addOnHover(std::function<void(Button&, HoverState)> func);
With your version the parameter func
is a non-const lvalue, and when you call it like this b.addOnHover(hoverOver)
hoverOver
is a pointer to function so a temporary object is created of type std::func
(rvalue) which, as I have said, cannot be bound to a non-const lvalue reference. 在您的版本中,参数
func
是一个非常量左值,当您这样调用它时, b.addOnHover(hoverOver)
hoverOver
是一个函数指针,因此会创建一个类型为std::func
(rvalue)的临时对象,该对象为我已经说过,不能绑定到非常量左值引用。
Btw, i figured this out when I saw the error message, so it is important to try to go through the error. 顺便说一句,当我看到错误消息时我发现了这一点,因此尝试解决错误很重要。
There are two potential issues I can see. 我可以看到两个潜在的问题。
1) The type of the 'parameter' (ie Button) void addOnHover(std::function<void(Button&, HoverState)>& func);
1)'参数'(即Button)的类型
void addOnHover(std::function<void(Button&, HoverState)>& func);
is more specific than the value you give ButtonBase
in void hoverOver(game::ButtonBase& button, game::HoverState state)...
比您在
void hoverOver(game::ButtonBase& button, game::HoverState state)...
给ButtonBase
赋予的值更具体void hoverOver(game::ButtonBase& button, game::HoverState state)...
This is as if you are assigning a ptr to the parent class to a ptr to a child class. 就像您要为父类分配一个ptr,给子类分配一个ptr。
If you had used plain values, a ButtonBase&
parameter should accept Button&
, but not the other way around. 如果使用普通值,则
ButtonBase&
参数应接受Button&
,但不能接受。 In other words, I think you should have 换句话说,我认为您应该
void addOnHover(std::function<void(ButtonBase&, HoverState)>& func);
and 和
void hoverOver(game::Button& button, game::HoverState state)...
(or void hoverOver(game::ButtonBase& button, game::HoverState state)...
) void hoverOver(game::Button& button, game::HoverState state)...
(或void hoverOver(game::ButtonBase& button, game::HoverState state)...
)
2) even if the types do match, std::function
does not automatically accept conversion from a function pointer or lambda of the same type. 2)即使类型匹配,
std::function
也不会自动接受来自相同类型的函数指针或lambda的转换。 It's a pain of using std::function
as it is now in c++11. 使用
std::function
很痛苦,就像在c ++ 11中一样。 You need to assign the function to a std::function
object first or call the constructor as you did. 您需要先将函数分配给
std::function
对象,或者像您那样调用构造函数。 This is, unfortunately, unlike the case where you can have std::string
accept const char*
. 不幸的是,这不同于可以让
std::string
接受const char*
。
I guess what your std::function
usage or the wrapper does is a type cast. 我猜你的
std::function
用法或包装器是类型转换。 So compiler accepts it because you explicitly told the compiler the cast should be OK. 所以编译器接受它,因为您明确告诉编译器强制转换应该可以。 It doesn't mean the types are actually compatible.
这并不意味着类型实际上是兼容的。
Regarding the second issue, I have asked a related question about how to let std::function
accept a function(plain, lambda etc) of the corresponding type: How to make C++11 functions taking function<> parameters accept lambdas automatically . 关于第二个问题,我问了一个相关的问题,关于如何让
std::function
接受相应类型的函数(普通,lambda等): 如何使带有function <>参数的C ++ 11函数自动接受lambda 。 The answer I got most is that I shouldn't use std::function
or expect to use it that way. 我最大的答案是我不应该使用
std::function
或期望以这种方式使用它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.