C++传递函数作为具有多态类型的参数
C++ passing function as argument with polymorphic type
>我有函数
void addOnHover(std::function<void(Button&, HoverState)>& func);
void addOnHover(void(*fptr)(Button&, HoverState));
按钮继承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);
或者如果我将悬停从game::ButtonBase&
更改为game::Button&
,我可以让它工作,但我想知道是否可以在没有如此冗长的情况下完成(std::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);
但我不确定它是否会正常运行
您遇到的一个问题是,非常量左值引用不能绑定到右值。
做
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) 的临时对象,正如我所说,该对象不能绑定到非常量左值引用。
顺便说一句,当我看到错误消息时,我想通了这一点,因此尝试通过错误很重要。
我可以看到两个潜在的问题。
1) "参数"的类型(即按钮)void addOnHover(std::function<void(Button&, HoverState)>& func);
比您给出的值更具体ButtonBase
void hoverOver(game::ButtonBase& button, game::HoverState state)...
这就像您将父类的 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 的转换。使用std::function
就像现在在 c++11 中一样很痛苦。您需要先将函数分配给std::function
对象,或者像以前一样调用构造函数。不幸的是,这与您可以接受的情况不同std::string
接受const char*
.
我想您的std::function
用法或包装器的作用是类型转换。所以编译器接受它,因为你明确告诉编译器强制转换应该没问题。这并不意味着这些类型实际上是兼容的。
关于第二个问题,我问了一个关于如何让std::function
接受相应类型的函数(普通函数、lambda 等)的相关问题:如何使 C++11 函数接受函数<>参数自动接受 lambda。我得到最多的答案是我不应该使用std::function
或期望以这种方式使用它。
- 对于多态类型T,如何在没有类型T实例的情况下获得指向T的虚拟表的指针
- 哈希多态类型的正确方式
- C++ 2D shared_ptr数组使用抽象多态类型初始化
- 一个类似 std::访问的函数,用于访问多态类型
- 将unique_ptr返回到多态类型
- 为什么删除的复制构造函数不允许使用其他具有多态类型的构造函数?
- Sean Parent:对于继承层次结构中的多态类型,具有可变对象是极端的例外
- 通过指向非多态类型的基类的指针获取已分配内存的地址
- 如何在代码块 IDE 上修复此警告,警告:按值 [-Wcatch-value=] 捕获多态类型"类 std::d omain_error"
- 不是多态类型,或者为什么我们在这里需要虚拟析构函数?
- 游戏引擎:Dynamic_cast-对象类不是多态类型
- 使用decltype的动态多态类型演绎
- 编译器如何知道为多态类型选择哪个函数
- 多态类型的连续存储
- 如何在gSOAP中绑定多态类型
- 防止谷物写入多态类型数据
- C++传递函数作为具有多态类型的参数
- 返回不带动态内存分配的多态类型
- 符合标准的编译器是否可以拒绝包含非多态类型向下转换dynamic_cast代码
- 在循环中使用无变量多态类型进行优化