即使我担心你会告诉我这个话题已被多次讨论,我敢问它,因为我无法生成解决方案。可能我只是在寻找错误的东西......
假设我有一个从某个外部函数接收“模式”的函数。根据模式,该函数将调用同一对象的不同成员函数。对于我来说,这对于我没有任何参数的成员函数很有效,但我没有找到如何将它扩展到带参数的成员。在现实世界的应用程序中,参数不是int / float而是更复杂的类,并且调用嵌套在不同的循环中,所以我需要多次放置switch语句,这些都是我认为很难看的。
问题A:是否可以使用基于现有设计的参数轻松添加对成员函数的支持?如果是,那怎么做呢?如果可能,没有外部库......
问题B:这是一种完全错误/错误的做法吗?我该怎么做得更好?
非常感谢您的帮助和解释。
克里斯
标题摘录:
typedef void (Object::*memberFunction)();
class Object
{
void memberFnNoArg();
void memberFnWithIntArg(int arg);
void memberFnWithFloatArg(float arg);
}
cpp excerpt:
void function()
{
int mode = getModeFromSomewhere();
int intArg = 33;
float floatArg = 66.6;
switch(mode)
{
case 1:
process(&Object::memberFnNoArg);
break;
case 2:
process(&Object::memberFnWithIntArg, ???); // how can I pass arg?
break;
case 3:
process(&Object::memberFnWithFlaotArg, ???); // how can I pass arg?
break;
default:
// do nothing;
}
}
void process(Object::memberFunction func)
{
Object object;
// loops, called several times, ...
(object.*func)(); // how do I handle different arguments?
}
答案 0 :(得分:2)
看一下std :: function和std :: bind,它们似乎完全符合你的需要。
编辑:
std::function<void(Object &)> f = &Object::memberFnNoArg;
std::function<void(Object &)> f2 = std::bind(&Object::memberFnWithIntArg, _1, 22);
Object o;
f(o);
f2(o);
据我记得,应该在盒子里工作。 这是你需要的吗?
答案 1 :(得分:2)
将算法包装在仿函数中是正确的方法,std::function
是标准库提供的一个很好的仿函数。
但是,正如Tomek所建议的那样,使用boost::bind
甚至std::bind
是非常丑陋的IMO,并且在绑定多个参数时会迅速失控。
如果你有一个最近的编译器,你可以使用lambda代替,这使得Tomek的例子看起来像:
std::function<void(Object*)> f =
[](Object* const that){ that->memberFnNoArg(); };
int int_value = 22;
std::function<void(Object*)> f2 =
[int_value](Object* const that){ that->memberFnIntArg(int_value); };
Object o;
f(&o);
f2(&o);
设置lambda有几个字符,但成员访问语法非常自然,你做出更改的方式很明显。
当然,如果你真的想要,可以让参数作为对象的引用,但我更喜欢这里的指针。
答案 2 :(得分:1)
您可以使用可变参数模板函数:
template <typename... Args>
void process(void (Object::*func)(Args...),Args... args)
{
Object object;
// loops, called several times, ...
(object.*func)(args...);
}
以下是一个完整的例子:
#include <iostream>
struct Object
{
void memberFnNoArg()
{
std::cout << "Object::memberFnNoArg()\n";
}
void memberFnWithIntArg(int arg)
{
std::cout << "Object::memberFnWithIntArg(" << arg << ")\n";
}
void memberFnWithFloatArg(float arg)
{
std::cout << "Object::memberFnWithFloatArg(" << arg << ")\n";
}
};
template <typename... Args>
void process(void (Object::*func)(Args...),Args... args)
{
Object object;
// loops, called several times, ...
(object.*func)(args...);
}
int main()
{
process(&Object::memberFnNoArg);
process(&Object::memberFnWithIntArg,5);
process(&Object::memberFnWithFloatArg,2.7F);
return 0;
}
答案 3 :(得分:0)
我看到的一种方法是使用变量参数(非常类似于printf,sprintf就是这样)。 (或者可能使用stdc库,传递不同类型的列表。)
原因是,参数列表是函数指针类型的一部分,所以你基本上需要一个带有变量参数的进程函数,然后memberFunction可能也需要是那个类型之一。
以下是如何获取变量参数的简单(非成员)示例(成员函数基本上相同)。请参阅stdarg.h。
typedef void (*var_function)(int typearg, ...);
void print_arg(int typearg, ...)
{
va_list ap;
int i;
va_start(ap, typearg);
if (typearg==1) { // int
int i= va_arg(ap, int);
printf("%d ", i);
}
else
if (typearg==2) { // float
float f= va_arg(ap, float);
printf("%f ", f);
}
else
if (typearg==3) { // char *
char *s= va_arg(ap, char *);
printf("%s ", s);
}
....
va_end(ap);
}
// calling function with different types
int main()
{
print_arg(1, 999);
print_arg(2, 3.1415926);
print_arg(3, "Hello");
....
process(print_arg, 3, "via pointer);
答案 4 :(得分:0)
听起来像packaged_task。另请查看Tomek的建议。
虽然IRL我会先讨论一下你为什么需要它的问题。可能使用std::future
或其他更高级别的工具
答案 5 :(得分:0)
每个函数(memberFn **)都不能成为参数类的成员吗?
class BaseArg
{
virtual void Fn() = 0;
};
class IntArg : public BaseArg
{
void Fn();
};
class FloatArg : public BaseArg
{
void Fn();
};
void function()
{
int mode = getModeFromSomewhere();
BaseArg* pArg;
if ( mode ... ){
pArg = new IntArg( 33 );
}
else {
pArg = new FloatArg( 66.6 );
}
pArg->Fn(); // Call the right function without a switch
// and without knowing the arguments
}
答案 6 :(得分:0)
与其他答案相同,但要显示成员方法:
#include <iostream>
class Object
{
public:
void memberFnNoArg()
{
std::cout << "Object::memberFnNoArg()\n";
}
void memberFnWithIntArg(int arg)
{
std::cout << "Object::memberFnWithIntArg(" << arg << ")\n";
}
void memberFnWithFloatArg(float arg)
{
std::cout << "Object::memberFnWithFloatArg(" << arg << ")\n";
}
bool memberFnWithBoolReturn(int)
{
return true;
}
template <typename... Args>
void process(void (Object::*func)(Args...),Args... args);
// overload process
template <typename... Args>
bool process(bool (Object::*func)(Args...),Args... args);
};
template <typename... Args>
void process( void (Object::*func)(Args...),class Object* obj,Args... args)
{
(obj->*func)(args...);
}
template <typename... Args>
bool process( bool (Object::*func)(Args...),class Object* obj,Args... args)
{
return ((obj->*func)(args...)) ;
}
int main()
{
Object object;
process(&Object::memberFnNoArg,&object);
process(&Object::memberFnWithIntArg,&object,5);
process(&Object::memberFnWithFloatArg,&object,2.7F);
// overloaded process
printf("%d\n",process(&Object::memberFnWithBoolReturn,&object,1));
return 0;
}