Reputation: 445
I have some functions (simple for this example) with different paramaters:
int addNums(int a, int b) {
return a + b;
}
int squareNum(int a) {
return a * a;
}
I have a template class action
which has a function pointer which will eventually point to either of the above functions:
template<class T>
class action {
public:
std::string descriptionOfAction;
T functionPtr;
};
I have a class user
which should have some form of a container of action
s:
class user {
public:
std::string name;
//container of actions
};
In main
, I defined and initialized two action
s to correspond with the first two functions listed above:
action<int(*)(int, int)> addAction;
addAction.descriptionOfAction = "Add two numbers together";
addAction.functionPtr = addNums;
action<int(*)(int)> squareAction;
squareAction.descriptionOfAction = "Square a number";
squareAction.functionPtr = squareNum;
Now I want to insert both of these action
s into a user
s container of action
s:
user aUser;
aUser.name = "User's Name";
//insert "addAction" and "squareAction" to user's container of actions
Because of the templating, these action
s are not the same types. Is there an existing type of container to hold these? If not, is there a way to do something similar without templates? Ideally, when a user
"uses" one of the action
s in their container, the action
should be erased.
Upvotes: 0
Views: 877
Reputation: 1
Don't store pointers to functions as void*
. A pointer-to-function is not the same as a pointer-to-variable.
If you want to store multiple types in one variable, use std::variant
if you can use C++17, otherwise use a union
if you can't.
Upvotes: 0
Reputation: 774
The problem here is that functions have different arity (i.e., the number of arguments).
It's not much of a problem to put your functions into some container. You can always put your functions into an std::vector<void*>
(the compiler does not care), but then... what? What's the plan?
You will also need to add function arity to the same container, so it transforms to std::vector<std::pair<void*, unsigned int>>
(function pointer + arity). This automatically complicates your action adding, since you will obviously won't want to specify the arity by hand, and you will want to automate this in order to avoid any human error. This will involve templates. Moreover, you will need to manually inspect the arities and pass the appropriate number of parameters. This will be error prone, too.
The most simple approach would be to define some
struct my_function_interface {
virtual int operator()(<all your parameters here>) = 0;
};
And then define your actions in term of that interface. This is a classic OOP solution, which abstracts away all your problems. Moreover, it will most likely be more performant, since all your checks and special function invocations won't come for free. Here, you will have a single virtual function call.
Upvotes: 1