I am wondering if there is a way in C to write a function that will resolve object methods based on the method name alone (specific examples below). Run time or compile time resolution (such as templates) would both be acceptable. I have read a little bit about template metaprogramming, but I was hoping I might get some info as to whether that is even the appropriate direction for my problem before delving to deep into that.
Essentially, I am trying to write a function that will call non-static methods of a passed in object, such as this psuedocode:
exampleFunction(Object myObject, ObjectMethod myObjectMethod) {
// do some stuff here
myObject.myObjectMethod(arguments);
// do some more stuff here
}
In this case, I cannot hard-code a method into exampleFunction
and simply have every object that I call it with have that method name. I must have the flexibility to call exampleFunction
with a variety of methods, and have each of those methods properly resolve. Further, I must be able to resolve methods, and those methods must be non-static. In my case, I must be able to modify internal, private object members on the method call. Without going into the details, these constraints are an artifact of the system I am working on that I cannot change.
As I previously stated, both compile time and run time solutions are acceptable. So something like this with templates would work perfectly well in my case as well:
template <ObjectMethodName methodName>
exampleFunction(Object myObject) {
// do some stuff here
myObject.methodName(arguments);
// do some more stuff here
}
Any thoughts on whether this is possible, as well as information on possible implementation would be appreciated.
CodePudding user response:
You can make exampleFunction
a function template that has the first parameter of type of the object, the second parameter can be a reference to a pointer to a member function and the third parameter is a function parameter pack that denotes the arguments to be passed when calling the member function.
#include <iostream>
class Actions {
public:
Actions(){}
void doSmthg(){
std::cout<<"do something called"<<std::endl;
}
void multipleArgs(int, int)
{
std::cout<<"multiple int args called"<<std::endl;
}
};
class Entity
{
public:
void func(double)
{
std::cout<<"func called"<<std::endl;
}
};
template<typename T, typename Callable, typename... Args>
void exampleFunction(T obj, const Callable& callable, const Args&... args){
std::cout<<"exampleFunction called"<<std::endl;
//call the function on the passed object
(obj.*callable)(args...);
}
int main()
{
Actions action;
exampleFunction(action, &Actions::doSmthg); //calls doSmthg member function with 0 arguments
exampleFunction(action, &Actions::multipleArgs, 5,7);//calls multipleArgs member function with 2 int arguments
Entity e;
exampleFunction(e, &Entity::func,4.4); //calls func member function
}
The output of the above program is:
exampleFunction called
do something called
exampleFunction called
multiple int args called
exampleFunction called
func called
CodePudding user response:
It's possible to pass a pointer-to-member-function as a template parameter.
Here is one example approach.
#include <iostream>
struct Foo {
void print() {
std::cout << "Foo\n";
}
void printVal(int val) {
std::cout << "val = " << val << "\n";
}
};
template <auto F, typename T, typename... Args>
void exampleFunc(T& obj, Args&&... args) {
(obj.*F)(args...);
}
int main()
{
Foo foo;
exampleFunc<&Foo::print>(foo);
exampleFunc<&Foo::printVal>(foo, 5);
}
Using auto
template parameters requires c 17.