How to create map<string, class::method> in c++ and be able to search for function and call it?

て烟熏妆下的殇ゞ 提交于 2019-11-30 17:39:32

Well, I'm not a 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 have understood correctly that you want a method pointer, not a function/static method pointer.

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.

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);

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.

Dario

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); 

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.

//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);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!