3

尽管我害怕你会告诉我这个话题已经讨论过好几次了,但我还是敢问,因为我无法产生解决方案。可能我只是在寻找错误的东西......

假设我有一个从某个外部函数接收“模式”的函数。根据模式,函数将调用同一对象的不同成员函数。对于没有任何参数的成员函数,这对我来说效果很好,但我没有找到如何将它扩展到有参数的成员。在现实世界的应用程序中,参数不是 int/float 而是更复杂的类,并且调用嵌套在不同的循环中,所以我需要多次放置我认为丑陋的 switch 语句。

问题 A:是否可以在现有设计的基础上轻松添加对带有参数的成员函数的支持?如果是,如何做到这一点?如果可能没有外部库...

问题 B:这是一个完全错误/糟糕的方法吗?我该怎么做才能做得更好?

非常感谢您的帮助和解释。

克里斯

标题摘录:

typedef void (Object::*memberFunction)();

class Object
{
    void memberFnNoArg();
    void memberFnWithIntArg(int arg);
    void memberFnWithFloatArg(float arg);
}

cpp摘录:

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?
}
4

7 回答 7

2

将算法包装在仿函数中是正确的方法,并且std::function是标准库提供的一个很好的仿函数。

但是,使用boost::bindor even std::bind,正如 Tomek 所建议的那样,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,但成员访问语法非常自然,并且很明显您如何进行更改。

当然,如果你真的想要,你可以让参数成为对象的引用,但我更喜欢这里的指针。

于 2013-06-05T14:34:59.727 回答
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);

据我所知,应该开箱即用。这是你需要的吗?

于 2013-06-04T09:54:55.920 回答
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;
}
于 2013-06-04T13:15:34.487 回答
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

}
于 2013-06-04T13:06:58.207 回答
0

听起来像packaged_task。另请查看 Tomek 的建议。

虽然 IRL 我会继续问很多关于你为什么首先需要它的问题。std::future可能使用或其他更高级别的设施可以更好地覆盖您的工作,

于 2013-06-04T11:04:13.907 回答
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);
于 2013-06-04T09:22:35.707 回答
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;
}
于 2017-02-15T15:44:20.443 回答