我正试图找到一个重构解决方案以下场景。我有许多重复的函数,每个都做完全相同的事情,除了在一个类实例上调用不同的成员函数,这个类实例只在最内部作用域中可用。
struct MyObject
{
void Function1() {};
void Function2() {};
void Function3() {};
void Function4() {};
};
std::vector<MyObject *> objects;
void CommandHandler1()
{
if (true) // lots of preconditions
{
size_t id = 0;
if (true) // lots of lookup code for id
{
MyObject *myObject = objects.at(id);
myObject->Function1();
}
// refresh code
}
// cleanup code
}
// another CommandHandler2, CommandHandler3, CommandHandler4, etc. doing the same thing but for a different member function.
我想避免多个CommandHandlerx的重复,因为它们非常相似。我所尝试的是传递std::函数来处理任何实例,因为我不能绑定到特定的实例。对这个问题的回答意味着应该编译下面的小程序。
#include <functional>
void CommandHandler(std::function<void(MyObject *)> func)
{
if (true) // lots of preconditions
{
size_t id = 0;
if (true) // lots of lookup code for id
{
MyObject *myObject = objects.at(id);
func(myObject);
}
}
// cleanup code
}
void MenuHandler(int chosen)
{
switch (chosen)
{
case 0: CommandHandler( &MyObject::Function1); break;
case 1: CommandHandler( &MyObject::Function2); break;
case 2: CommandHandler( &MyObject::Function3); break;
case 3: CommandHandler( &MyObject::Function4); break;
}
}
int main()
{
MyObject *obj1 = new MyObject;
MyObject *obj2 = new MyObject;
objects.push_back(obj1);
objects.push_back(obj2);
MenuHandler(1);
delete obj1; delete obj2;
return 0;
}
不幸的是,这不能构建。我认为,因为我没有绑定特定的this
指针:
C:Program Files (x86)Microsoft Visual Studio12.0VCincludefunction (506): error C2664: 'void std::_Func_class<_Ret,MyObject *>::_Set(std::_Func_base<_Ret,MyObject . sh)*> *)':无法将参数1从'_Myimpl *'转换为'std::_Func_base<_Ret,MyObject *> *'
我的问题是(1)我是否在上面的std::函数尝试中做错了什么,或者(2)是否有任何其他模式可以重构这个场景?
您的代码与GCC一起工作,因此它很可能是MSVC实现std::function
的特性。我将提供一些变通方法。
如果函数1–4真的都遵循相同的签名,你根本不需要std::function
,一个普通的成员函数指针就可以了:
void CommandHandler(void (MyObject::*func)())
{
if (true) // lots of preconditions
{
size_t id = 0;
if (true) // lots of lookup code for id
{
MyObject *myObject = objects.at(id);
(myObject->*func)();
}
}
// cleanup code
}
如果你确实需要一个不透明的可调用对象(例如,因为你绑定了一些参数),你应该能够使用std::mem_fn
为std::function
获得一个合适的初始化器:
void MenuHandler(int chosen)
{
switch (chosen)
{
case 0: CommandHandler( std::mem_fn(&MyObject::Function1)); break;
case 1: CommandHandler( std::mem_fn(&MyObject::Function2)); break;
case 2: CommandHandler( std::mem_fn(&MyObject::Function3)); break;
case 3: CommandHandler( std::mem_fn(&MyObject::Function4)); break;
}
}