я использую muParser для синтаксического анализа математических выражений, и я хотел бы добавить функцию в синтаксический анализатор, реализация которой будет обеспечиваться нестатической функцией-членом класса. Этот отрывок из пример программы должен дать представление о том, что я хочу сделать:
struct MyClass { // some boilerplate omitted
double make_a_value(double a, double b); // implemented elsewhere
};
int main(const int argc, const char** argv) {
MyClass instance;
mu::Parser p;
p.DefineFun("f", MORE_MAGIC(MyClass::make_a_value, &instance));
p.SetExpr("f(3, 2)");
std::cout << p.Eval() << std::endl;
}
где MORE_MAGIC(...)
означает что-то с подписью double f(double arg1, double arg2)
что эквивалентно звонку instance->make_a_value(arg1, arg2)
, Я не знаю что MORE_MAGIC
должно быть для того, чтобы это работало. Это суть моего вопроса.
Второй аргумент DefineFun
может иметь любую из следующих сигнатур функций:
double f()
double f(double)
double f(double, double)
double
аргументыdouble f(double*, int)
где первый указатель является массивом и int
это длинаdouble f(const char*)
double f(const char*, double)
double f(const char*, double)
К сожалению, ни один из них не включает void*
параметр данных, который я могу использовать для передачи в экземпляре. Мне пришло в голову подорвать double*
передать экземпляр, но проблема в том, что muParser не позволяет мне заранее определять значение, которое будет передано функции; передаются только аргументы, взятые из проанализированного выражения.
Из прочтения нескольких других постов (1, 2, 3, 4, 5Мне кажется, что мне нужна связанная функция, и предпочтительный способ сделать это (в C ++ 98) boost::bind
, Но я пытался заменить MORE_MAGIC(...)
с boost::bind(&wrapper, _1, _2, &instance)
, с
double wrapper(double a, double b, MyClass* p) {
return p->make_a_value(a, b);
}
(надеюсь, правильный синтаксис) и я получаю ошибки компилятора:
/usr/include/muParserBase.h:134:95: error: no matching function for call to ‘mu::ParserCallback::ParserCallback(boost::_bi::bind_t<double, double (*)(double, double, MyClass*), boost::_bi::list3<boost::arg<1>, boost::arg<2>, boost::_bi::value<MyClass*> > >&, bool&)’
AddCallback( a_strName, ParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars() );
и так далее. Ик.
Я думаю, проблема в том, что boost::bind
возвращает boost::function
в то время как мне нужна стандартная функция, и в соответствии с этот ответ более или менее невозможно получить стандартную функцию от boost::function
без некоторых void*
спрятать указатель экземпляра. Но я не уверен, что правильно понимаю, имея небольшой опыт работы с Boost, поэтому мой предварительный вопрос: может ли кто-нибудь подтвердить, что boost::bind
просто не буду делать то, что мне нужно сделать?
И мой главный вопрос: есть ли любой способ вообще сделать это? Даже если это связано с тайными секретами волшебства C ++? (Или же *удушье* переход на C ++ 11?)
Похоже, API muParser, к сожалению, не готов к C ++.
В C ++ 11 Lambdas может «разлагаться», чтобы функционировать указатели, но это означает, что они должны быть без состояний, поэтому вы возвращаетесь в одно и то же место: вы не можете связывать дополнительные параметры.
Является ли muParser открытым исходным кодом? Возможно, есть вилка, которая уже исправила этот недостаток дизайна
О да, да, boost::bind
не могу нарушать законы физики сделай это для тебя