views:

64

answers:

7

I'm trying to create a map of string and method in C++, but I don't know how to do it. I would like to do something like that (pseudocode):

map<string, method> mapping =
{
  "sin", Math::sinFunc,
  "cos", Math::cosFunc,
  ...
};

...

string &function;
handler = mapping.find(function);
int result;

if (handler != NULL)
  result = (int) handler(20);

To be honest I don't know is it possible in C++. I would like to have a map of string, method and be able to search for function in my mapping. If given string name of function exists then I would like to call it with given param.

A: 

You can certainly coax the map<> container to map strings to function pointers. But that is a really hard way of doing something fairly simple.

Create an enum of all the function names. Map the string names to the enum values. Then use a switch statement to call the functions based on the enum value. You'll save a lot of hair from turning grey.

Amardeep
A: 

See this question. The most convenient notation for method is function<signature> where function is either included in boost or in <utility> under C++0x.

In your case, the signature would be like this.

map<string, function<double (double)> map; ...

map["sin"](1.0); 
Dario
+1  A: 

The easiest way would be to use boost::function:

#include <map>
#include <string>
#include <boost/function.hpp>

using namespace std;

// later...

map<string, boost::function<double(double)> > funcs;
funcs["sin"] = &Math::sinFunc;

It gets slightly more complex if you're using member functions - boost::lambda can help:

#include <map>
#include <string>
#include <boost/function.hpp>
#include <boost/lambda/bind.hpp>

using namespace std;
namespace l = boost::lambda;

// later...

Math *m = new Math();
map<string, boost::function<double(double)> > funcs;
funcs["sin"] = l::bind(&Math::sinFunc, m, l::_1);
bdonlan
Why would you use `boost::lambda::bind` instead of just `boost::bind`?
caspin
I just turn to boost::lambda for all my function-binding needs. It's easier than learning two separate libraries whose functionality overlaps :)
bdonlan
A: 

I think this would work, assuming your function returns int and takes a single int parameter:

map<string, int(*func)(int)>

If the function parameter types or return values differ, I don't think you could do this though.

Eric Petroelje
+2  A: 

This is indeed possible in C++, thanks to function pointers. Here's a simple example:

  std::string foo() { return "Foo"; }
  std::string bar() { return "Bar"; }

  int main()
  {
      std::map<std::string, std::string (*)()> m;

      // Map the functions to the names
      m["foo"] = &foo;
      m["bar"] = &bar;

      // Display all of the mapped functions
      std::map<std::string, std::string (*)()>::const_iterator it = m.begin();
      std::map<std::string, std::string (*)()>::const_iterator end = m.end();

      while ( it != end ) {
          std::cout<< it->first <<"\t\""
              << (it->second)() <<"\"\n";
          ++it;
      }
  }

This gets more tricky when dealing with functions with different return types and arguments. Also, if you are including non-static member functions, you should use Boost.Function.

Justin Ardini
A: 
//pick one
typedef float (*func_type_1)(float);
typedef boost::function<float(float)> func_type_2;

std::map<std::string,func_type> fm;
fm["sin"] = &Math::sin;
fm["cos"] = &Math::cos;

auto f = fm[str];
result = f(42);
caspin
A: 

Well, I'm not the member of the popular here Boost Lovers Club so here it goes - in raw C++.

#include <map>
#include <string>

struct Math
{
    double sinFunc(double x) { return 0.33; };
    double cosFunc(double x) { return 0.66; };
};

typedef double (Math::*math_method_t)(double);
typedef std::map<std::string, math_method_t> math_func_map_t;

int main()
{

    math_func_map_t mapping;
    mapping["sin"] = &Math::sinFunc;
    mapping["cos"] = &Math::cosFunc;

    std::string function = std::string("sin");
    math_func_map_t::iterator x = mapping.find(function);
    int result = 0;

    if (x != mapping.end()) {
        Math m;
        result = (m.*(x->second))(20);
    }
}

That's obviously if I understood properly that you want a method pointer, not a function/static method pointer.

Dummy00001
BTW that method also works with virtual functions. That is also the case where in C++ a pointer cannot be cast to long: for pointers to virtual methods compiler puts something extra into the pointer to allow for polymorphism.
Dummy00001