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
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
but if I do 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
as per Bolov request, here is compiler error when passing 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
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.
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);
is more specific than the value you give ButtonBase
in 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.
If you had used plain values, a ButtonBase&
parameter should accept Button&
, but not the other way around. 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)...
)
2) even if the types do match, std::function
does not automatically accept conversion from a function pointer or lambda of the same type. It's a pain of using std::function
as it is now in c++11. You need to assign the function to a std::function
object first or call the constructor as you did. This is, unfortunately, unlike the case where you can have std::string
accept const char*
.
I guess what your std::function
usage or the wrapper does is a type cast. 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 . The answer I got most is that I shouldn't use std::function
or expect to use it that way.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.