C++如何推广类函数参数来处理多种类型的函数指针?

Æle*_*lex 2 c++ templates pointers abstraction function

我不知道我所要求的是可行的,愚蠢的还是简单的.我最近才开始住在模板函数和类中,我想知道下面的场景是否可行:一个包含要调用的函数指针的类.函数指针不能是特定的,而是抽象的,因此无论何时调用类的构造函数,它都可以接受不同类型的函数指针.当调用类的execute函数时,它会使用参数(或参数)执行在构造时分配的函数指针.基本上,抽象在整个设计中保留,并在用户上留下要传递的函数指针和参数.以下代码尚未经过测试,只是为了演示我正在尝试做的事情:

void (*foo)(double);
void (*bar)(double,double);
void (*blah)(float);

class Instruction
{
    protected:
      double var_a;
      double var_b;
      void (*ptr2func)(double);
      void (*ptr2func)(double,double);  
    public:
      template <typename F> Instruction(F arg1, F arg2, F arg3)
      {
         Instruction::ptr2func = &arg1;
         var_a = arg2;
         var_b = arg3;
      };    
      void execute()
      {
         (*ptr2func)(var_a);
      };
};
Run Code Online (Sandbox Code Playgroud)

我不喜欢我必须在可能的可重载函数指针类中保留一个列表的事实.我怎么可能改进上面的内容以尽可能地概括它,以便它可以与任何类型的函数指针一起使用?请记住,我将保留这些实例化对象的容器并按顺序执行每个函数指针.谢谢 !编辑:也许这个类应该是它自己的模板,以便于使用许多不同的函数指针?编辑2:我找到了解决问题的方法,仅供将来参考,不知道它是否正确,但它有效:

class Instruction
{
  protected:
    double arg1,arg2,arg3;
  public:
    virtual void execute() = 0;
};

template <class F> class MoveArm : public Instruction
{
  private:
    F (func);    
  public:
   template <typename T> 
   MoveArm(const T& f,double a, double b)
   {
     arg1 = a;
     arg2 = b;
     func = &f;
   };

   void execute()
   {
     (func)(arg1,arg2);
   };
};
Run Code Online (Sandbox Code Playgroud)

但是在导入函数时,它们的函数指针需要是typedef'd:

void doIt(double a, double b)
{
   std::cout << "moving arm at: " << a << " " << b << std::endl;
};

typedef void (*ptr2func)(double,double);

int main(int argc, char **argv) {

   MoveArm<ptr2func>  arm(doIt,0.5,2.3);
   arm.execute();

   return 0;
}
Run Code Online (Sandbox Code Playgroud)

rek*_*o_t 5

如果你能使用的C++ 0x和可变参数模板,您可以通过使用组合实现这一点std::function,std::bind和完美转发:

#include <iostream>
#include <functional>

template <typename Result = void>
class instruction
{
public:
        template <typename Func, typename... Args>
        instruction(Func func, Args&&... args)
        {
                m_func = std::bind(func, std::forward<Args>(args)...);
        }

        Result execute()
        {
                return m_func();
        }
private:
        std::function<Result ()> m_func;
};

double add(double a, double b)
{
        return (a + b);
}

int main()
{
        instruction<double> test(&add, 1.5, 2.0);
        std::cout << "result: " << test.execute() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

输出示例:http://ideone.com/9HYWo

在C++ 98/03中,如果您需要支持可变数量的参数,那么您很可能需要自己重载构造函数以获得最多N个参数.你也可以使用boost::functionboost::bind不是std::等价物.然后还存在转发问题的问题,因此要完成转发,您需要根据需要支持的参数量进行指数级的重载.Boost有一个预处理器库,您可以使用它来生成所需的重载,而无需手动编写所有重载; 但这很复杂.

下面是一个如何使用C++ 98/03的例子,假设传递给它的函数instruction不需要通过可修改的引用来获取参数,为此,你还需要重载P1& p1而不是仅仅const P1& p1.

#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>

template <typename Result = void>
class instruction
{
public:
        template <typename Func>
        instruction(Func func)
        {
                m_func = func;
        }

        template <typename Func, typename P1>
        instruction(Func func, const P1& p1)
        {
                m_func = boost::bind(func, p1);
        }

        template <typename Func, typename P1, typename P2>
        instruction(Func func, const P1& p1, const P2& p2)
        {
                m_func = boost::bind(func, p1, p2);
        }

        template <typename Func, typename P1, typename P2, typename P3>
        instruction(Func func, const P1& p1, const P2& p2, const P3& p3)
        {
                m_func = boost::bind(func, p1, p2, p3);
        }

        Result execute()
        {
                return m_func();
        }
private:
        boost::function<Result ()> m_func;
};

double add(double a, double b)
{
        return (a + b);
}

int main()
{
        instruction<double> test(&add, 1.5, 2.0);
        std::cout << "result: " << test.execute() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

示例:http://ideone.com/iyXp1