Как создать карту <string, class :: method> в c ++ и уметь искать функцию и вызывать ее? - PullRequest
13 голосов
/ 24 июня 2010

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

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

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

Ответы [ 7 ]

17 голосов
/ 25 июня 2010

Ну, я не являюсь членом популярного здесь Клуба любителей ускорения, так что здесь - в сыром 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);
    }
}

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

6 голосов
/ 24 июня 2010

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

  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.

1 голос
/ 24 июня 2010

Самый простой способ - использовать 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);
0 голосов
/ 24 июня 2010
//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);
0 голосов
/ 24 июня 2010

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

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

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

0 голосов
/ 24 июня 2010

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

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

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

map["sin"](1.0); 
0 голосов
/ 24 июня 2010

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

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

...