map of pointers to functions of different return t

2019-04-10 02:47发布

I am looking for a way to call different functions by a string input.

I have a map that ties each unique string to a function pointer and a lookup function to search the map and return a pointer if found.

Now the trick is, I need a way to store and return pointers to functions with at least different return types, if possible, also with different signatures.

The usage would be:

Get a string input from a network socket -> find and execute the found function -> shove the result straight back into the socket to be serialized and sent, not caring what actually happened.

Is this doable? If not, how would one approach this task?

7条回答
爷、活的狠高调
2楼-- · 2019-04-10 03:27

While you can't store different function pointers, you can store objects which contain those functions.

#include <iostream>
#include <cmath>
#include <map>
#include <string>
using namespace std;

class Functor{
public:
    template<class T>
    void operator()(T data){}
};
template<class T>
class BaseFunctor : public Functor{
public:
    virtual void CallFunction(T data){ }
};
class FunctionPointer1 : public BaseFunctor<void *>{
public:
    void doFunction1(){
        cout << "Do Function 1"<<endl;
    }
    template<class T>
    void CallFunction(T data){ doFunction1(); }
    template<class T>
    void operator()(T data){ this->CallFunction(data); }
};

class FunctionPointer2 : public BaseFunctor<int>{
public:
    void doFunction2(int variable){ cout << "Do function 2 with integer variable" << variable <<endl; }
    template<class T>
    void CallFunction(T data) { doFunction2(data);} 
    template<class T>
    void operator()(T data){ this->CallFunction(data); }
};

class FunctionPerformer{
    private:
       map<string,Functor> functions;
    public:
       FunctionPerformer(){
         //init your map.
            FunctionPointer1 function1;
        FunctionPointer2 function2;
            //-- follows
        functions["Function1"] = function1;
        functions["Functions2"] = function2;
            //-- follows
       }
       Functor getFunctionFromString(string str){
                return functions[str]
       }
};
int main(int argc, char *argv[])
{
    map<string,Functor> functions;
    FunctionPerformer performer;

    Functor func1, func2; // to hold return values from perfomer()
    FunctionPointer1 *fn1; // to casting and execute the functions
    FunctionPointer2 *fn2; // to casting and execute the functions
    func1 = performer.getFunctionFromString("Function1");//get data
    func2 = performer.getFunctionFromString("Function2");

    //following two lines to cast the object and run the methods
    fn1 = reinterpret_cast<FunctionPointer1 *>(&func1);
    (*fn1)(NULL);

    //following two lines to cast the object and run the methods
    fn2 = reinterpret_cast<FunctionPointer2 *>(&func2);
    (*fn2)(10);

    system("Pause");
    return 0;
}

I think the edited part makes it clearer? This code can be optimized a little. Play around with it.

查看更多
三岁会撩人
3楼-- · 2019-04-10 03:30

No, it's really not doable, you need a real interpreted language if you want to do something like this. As soon as the signature is not constant then you need something a lot more involved.

查看更多
太酷不给撩
4楼-- · 2019-04-10 03:37

Can't you use specialization and templates to work around the issue?

template <class T>
T FooBar(void * params);

template<> int FooBar<int>( void * params ); 

template<> char FooBar<char>( void * params ); 
查看更多
太酷不给撩
5楼-- · 2019-04-10 03:40

How about making all those functions have the same signature? You could make all return types implement an interface, or use a collection, class, union or struct. Same for the arguments.

查看更多
仙女界的扛把子
6楼-- · 2019-04-10 03:44

This is doable in C++11 with Variadic Templates. Check my answer at https://stackoverflow.com/a/33837343/1496826

查看更多
Luminary・发光体
7楼-- · 2019-04-10 03:49

That can be done with a bit of boilerplate code in different ways. If the number of signatures is small enough you can hold multiple vectors of function pointers (one per function type) and then a map that maps the function name with a type identifier (used to select the vector) and the position within the vector.

The second option would be to store a boost::variant (again, if the set of signatures is small). You would need to provide a visitor object that evaluates the function (for each function type stored) and yields the result. The type is managed by the boost::variant type so there would be no need for the type tag to be stored in the map.

You can also use full type erasure and store in the map a tag determining the type of function to be called and a boost::any object storing the function pointer. You can use the type information to retrieve the pointer and execute the function, but you will have to manually handle the switch based on function type.

The simplest approach, on the other hand, is to write adapters that have a fixed interface. Then just store the pointers to the adapters in the map.

查看更多
登录 后发表回答