Как создать карту <string, class:: method> в С++ и уметь искать функцию и называть ее?

Я пытаюсь создать карту строки и метода на С++, но я не знаю, как это сделать. Я хотел бы сделать что-то вроде этого (псевдокод):

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

Честно говоря, я не знаю, возможно ли это на С++. Я хотел бы иметь карту строки, метода и иметь возможность искать функцию в моем сопоставлении. Если задано строковое имя функции существует, я хотел бы назвать его с заданным параметром.

Ответы

Ответ 1

Ну, я не являюсь членом популярного клуба Boost Lovers, поэтому здесь он идет - в сыром С++.

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

Это очевидно, если я правильно понял, что вы хотите указатель метода, а не указатель функции/статического метода.

Ответ 2

Это действительно возможно в С++ благодаря указателям на функции. Вот простой пример:

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

Это становится более сложным при работе с функциями с разными типами и аргументами возврата. Кроме того, если вы включаете нестатические функции-члены, вы должны использовать Boost.Function.

Ответ 3

Самый простой способ - использовать 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;

Это немного сложнее, если вы используете функции-члены - boost::lambda может помочь:

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

Ответ 4

Вы можете, конечно, уговорить map < > container отображать строки в указатели функций. Но это очень трудный способ сделать что-то довольно простое.

Создайте перечисление всех имен функций. Сопоставьте имена строк с значениями перечисления. Затем используйте оператор switch для вызова функций, основанных на значении перечисления. Вы сбережете много волос от серого.

Ответ 5

См. этот вопрос. Наиболее удобным обозначением для method является function<signature>, где function либо включается в boost, либо в <utility> в С++ 0x.

В вашем случае подпись будет такой.

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

map["sin"](1.0); 

Ответ 6

Я думаю, что это сработает, если ваша функция вернет int и возьмет один параметр int:

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

Если типы параметров функции или возвращаемые значения различаются, я не думаю, что вы могли бы это сделать.

Ответ 7

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