Как создать карту <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);