I do not know if what I am asking is doable, stupid or simple.
I’ve only recently started dwelling in template functions and classes, and I was wondering if the following scenario is possible:
A class which holds a function pointer to be called. The function pointer cannot be specific, but abstract, so that whenever the class’s Constructor is called, it may accept different kinds of function pointers. When the class’s execute function is called, it executes the function pointer allocated at construction, with an argument (or arguments).
Basically the abstraction is kept throughout the design, and left over the user on what function pointer and arguments to pass. The following code has not been tested, just to demonstrate what I’m trying to do:
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);
};
};
I do not like the fact I have to keep a list inside the class of possible overloadable function pointers. How could I possibly improve the above to generalize it as much as possible so that it can work with any kind of function pointer thrown at it ?
Bear in mind, I will want to keep a container of those instantiated objects and execute each function pointer in sequence.
Thank you !
Edit: Maybe the class should be a template it’self in order to facilitate use with many different function pointers?
Edit2: I found a way around my problem just for future reference, don’t know if it’s the right one, but it works:
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);
};
};
However when importing functions, their function pointers need to be 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;
}
If you can use C++0x and variadic templates, you can achieve this by using combination of
std::function,std::bindand perfect forwarding:Example with output: http://ideone.com/9HYWo
In C++ 98/03, you’d unfortunately need to overload the constructor for up-to N-paramters yourself if you need to support variable-number of arguments. You’d also use
boost::functionandboost::bindinstead of thestd::equivalents. And then there’s also the issue of forwarding problem, so to do perfect forwarding you’d need to do an exponential amount of overloads depending on the amount of arguments you need to support. Boost has a preprocessor library that you can use to generate the required overloads without having to write all the overloads manually; but that is quite complex.Here’s an example of how to do it with C++98/03, assuming the functions you pass to the
instructionwon’t need to take the arguments by modifiable reference, to do that, you also need to have overloads forP1& p1instead of justconst P1& p1.Example: http://ideone.com/iyXp1