我有一个模板类,它在构造函数中获取一个函数指针。类中的方法稍后将根据条件调用该函数。我可以拥有该类的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 ++中使用模板来做到这一点?
答案 0 :(得分:3)
我认为你的Value3
类迫使客户端提供一个Thread
参数这一事实是否函数指针在所有点接受一些设计缺陷的参数。你想要的是客户只传递他们需要的参数。
使用模板实现此目的的一种方法是使用模板特化来捕获必要的参数,如下所示:
int
从那里开始,专业化的其余部分几乎写出来。如果您可以处理开销,我建议使用std::function
实例化lambda,以便绑定template<class...>
class Thread;
template <class RET, class... ARGS>
class Thread<RET(*)(ARGS...)> {/*..*/}
的构造函数中收到的参数。这很好,因为它使Thread
中的保持类型保持一致。那么你不必尝试在Thread
的两个版本之间进行某种运行时切换
f()
当然,考虑到复制/移动两个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;
*我们现在已经了解到您的使用情况。我们非常抱歉你的运气