实例化一个模板类,该模板类在具有不同函数签名的构造函数中获取函数指针

时间:2017-05-26 11:17:53

标签: c++ templates function-pointers

我有一个模板类,它在构造函数中获取一个函数指针。类中的方法稍后将根据条件调用该函数。我可以拥有该类的2个对象,每个对象都使用具有不同签名的函数指针进行实​​例化吗?简化代码如下。

#include <iostream>
using namespace std;

template <class FUNC>
class Thread {
public:
    Thread(FUNC f1, int i)
      : f(f1), val(i) {};

    void run() {
        if (val == 1)
            f();
         else
            f(val); // here
     }
private:
     FUNC f;
     int val;
};

void print() {
    cout << "print" << endl;
}

void incr(int a) {
    cout << "incremented value is " << ++a << endl;
}

int main () {
    Thread<void(*)()> t1(print,1);
    t1.run();
    Thread<void(*)(int)> t2(incr,2);
    t2.run();
}

run()根据 val 决定调用哪个函数。两种可能的功能都有不同的签名。执行此操作时,我收到以下编译错误。

    testa.cpp: In member function 'void Thread<FUNC>::run() [with FUNC = void (*)()]':
    testa.cpp:33:   instantiated from here
    testa.cpp:16: error: too many arguments to function
    testa.cpp: In member function 'void Thread<FUNC>::run() [with FUNC = void (*)(int)]':
    testa.cpp:35:   instantiated from here
    testa.cpp:14: error: too few arguments to function

我该怎么做?有没有一种方法在c ++中使用模板来做到这一点?

2 个答案:

答案 0 :(得分:3)

我认为你的Value3类迫使客户端提供一个Thread参数这一事实是否函数指针在所有点接受一些设计缺陷的参数。你想要的是客户只传递他们需要的参数。

使用模板实现此目的的一种方法是使用模板特化来捕获必要的参数,如下所示:

int

从那里开始,专业化的其余部分几乎写出来。如果您可以处理开销,我建议使用std::function实例化lambda,以便绑定template<class...> class Thread; template <class RET, class... ARGS> class Thread<RET(*)(ARGS...)> {/*..*/} 的构造函数中收到的参数。这很好,因为它使Thread中的保持类型保持一致。那么你不必尝试在Thread的两个版本之间进行某种运行时切换

f()

Demo

当然,考虑到复制/移动两个template <class RET, class... ARGS> class Thread<RET(*)(ARGS...)> { public: using fptr_t = RET(*)(ARGS...); Thread(fptr_t fptr, ARGS... args) { f = [fptr, args...]{fptr(args...);}; } void run() { f(); } private: std::function<void(void)> f; }; 对象,这个代码对于生产环境应该变得更加复杂,但也会移动参数的语义来绑定到函数指针。

答案 1 :(得分:1)

在C ++ 98 * 中,最好的方法可能是void函数的模板类特化(零参数),并且单独用于一元(单个参数)函数:

List.toList

这种方法的好处是你不会将额外的变量放入一个不需要它们的类中(void函数类)。此外,由于我们的专业化编写方式,我们可以将template<class FN> class Thread; // void functions template <class RET> class Thread<RET(*)(void)> {/*..*/} // unary functions template <class RET, class ARG> class Thread<RET(*)(ARG)> {/*..*/} 的返回类型更改为与函数指针的返回类型相同:

run

还有一些测试:

template <class RET>
class Thread<RET(*)(void)> {
public:
    typedef RET(*fptr_t)(void);
    Thread(fptr_t fptr) : f(fptr) {}

    RET run() {
        return f();
    }
private:
     fptr_t f;
};

template <class RET, class ARG>
class Thread<RET(*)(ARG)> {
public:
    typedef RET(*fptr_t)(ARG);
    Thread(fptr_t fptr, ARG arg) : f(fptr), val(arg) {}

    RET run() {
        return f(val);
    }
private:
     fptr_t f;
     ARG val;
};

输出:

Thread<void(*)()> t1(&print);
t1.run();
Thread<void(*)(int)> t2(&incr,2);
t2.run();
Thread<int(*)(int)> t3(&get_val, 42);
int return_value = t3.run();
std::cout << "t3 returned " << return_value << std::endl;

Demo

*我们现在已经了解到您的使用情况。我们非常抱歉你的运气