开发者

C++: How to pass a generic function name?

I am building a program in c++ where the user can set a function to be called when user defined conditions are reached. I am only a little experienced with c++.

I know how to do this in python. You would simply define functions and put the names of said functions into a st开发者_Python百科ructure (I always used a dictionary). When you go to use the function, you would make a call similar to:

methods = { "foo" : foo, "bar" : bar } 
choice = input("foo or bar? ")
methods[choice]()

Any ideas on how to pull this off in c++ without having to hardcode everything?


You can use a map of function pointers:

void foo() { }
void bar() { }

typedef void (*FunctionPtr)();
typedef std::map<std::string, FunctionPtr> FunctionMap;

FunctionMap functions;
functions.insert(std::make_pair("foo", &foo));
functions.insert(std::make_pair("bar", &bar));

std::string method = get_method_however_you_want();

FunctionMap::const_iterator it(functions.find(method));
if (it != functions.end() && it->second)
    (it->second)();


Your Python code actually translates to C++ pretty much directly:

# Python:
# Create a dictionary mapping strings to functions
methods = { "foo" : foo, "bar" : bar } 
// C++:
// create a map, mapping strings to functions (function pointers, specifically)
std::map<std::string, void(*)()> methods; 
methods["foo"] = foo;
methods["bar"] = bar;

# Python
choice = input("foo or bar? ")
// C++:
std::string choice;
std::cout << "foo or bar? ";
std::cin >> choice;

# Python:
methods[choice]()
// C++
methods[choice]();

Python's dictionary is similar to C++'s map. They're both associative containers, mapping a value from one type to a value of another (in our case, string to function). In C++, functions aren't quite first-class citizens, so you can't store a function in a map, but you can store a pointer to a function. Hence the map definition gets a bit hairy, because we have to specify that the value type is a "pointer to a function which takes no arguments and returns void".

On a side note, it is assumed that all your functions have the same signature. We can't store both functions that return void and functions that return an int in the same map without some additional trickery.


You may have a look at function pointers:

http://www.newty.de/fpt/intro.html


Another option is function objects + inheritance:

#include <string>
#include <iostream>
#include <conio>
#include <exception>
//---------------------------------------------------------------------------

struct Method{
    virtual ~Method(){}

    virtual
    void operator() (void)=0;
};
struct foo: public Method{
    virtual ~foo(){}

    virtual
    void operator() (void){
        std::cout << "this is foo\n";
    }
};
struct bar: public Method{
    virtual ~bar(){}

    virtual
    void operator() (void){
        std::cout << "this is bar\n";
    }
};

Method* getMethodByName(std::string methName){
    if( methName == "foo" )
        return new foo();
    else if( methName == "bar" )
        return new bar();

    throw invalid_argument("Unknown method");
}
//---------------------------------------------------------------------------

int main(int argc, char* argv[])
{
    std::string choice;

    std::cout << "foo or bar?\n";
    std::cin >> choice;

    boost::shared_ptr<Method> method = getMethodByName(choice);
    (*method)();

    getch();
    return 0;
}

Though this requires boost's smart pointer lib. With vanilla C++:

    Method* method = getMethodByName( choice );
    try{
        (*method)();
        delete method;
    }
    catch(...){
        delete method;
    }

    getch();
    return 0;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜