Can I pass a member function to mu::Parser::DefineFun()?

359 views Asked by At

I'm using muParser to parse mathematical expressions, and I would like to add a function to the parser whose implementation will be provided by a non-static member function of a class. This excerpt from an example program should give an idea of what I want to do:

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

where MORE_MAGIC(...) stands for something with the signature double f(double arg1, double arg2) which is equivalent to calling instance->make_a_value(arg1, arg2). I don't know what MORE_MAGIC should be in order for this to work. That's the essence of my question.

The second argument of DefineFun can have any of the following function signatures:

  • double f()
  • double f(double)
  • double f(double, double)
  • and so on up to 10 double arguments
  • double f(double*, int) where the first pointer is an array and the int is its length
  • double f(const char*)
  • double f(const char*, double)
  • double f(const char*, double)

Unfortunately none of these include a void* data parameter that I can use to pass in an instance. It occurred to me to subvert a double* to pass the instance, but the problem is really that muParser doesn't let me pre-define a value to be passed to the function at all; only the arguments taken from the parsed expression get passed.

From reading several other posts (1, 2, 3, 4, 5) t seems that what I need is a bound function, and the preferred way to do it (in C++98) is boost::bind. But I've tried replacing MORE_MAGIC(...) with boost::bind(&wrapper, _1, _2, &instance), with

double wrapper(double a, double b, MyClass* p) {
    return p->make_a_value(a, b);
}

(hopefully correct syntax) and I get compiler errors:

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

and so on. Ick.

I guess the problem is that boost::bind returns a boost::function, whereas I need a standard function, and according to this answer it's more or less impossible to get a standard function from a boost::function without some void* to stash the instance pointer. But I'm not sure I'm understanding correctly, having little experience with Boost, so my preliminary question is: can anyone confirm that boost::bind simply will not do what I need it to do?

And my main question: is there any way at all to accomplish this? Even if it involves arcane secrets of C++ wizardry? (Or *gasp* switching to C++11?)

1

There are 1 answers

6
sehe On

Looks like the muParser API sadly isn't ready for C++.

In C++11 Lambdas can "decay" to function pointers, but this means they have to be stateless, so, you're back at the same spot: you can't bind extra parameters.

Is muParser open source? Perhaps there is a fork that has already amended this design flaw


Oh and, yes, boost::bind cannot break the laws of physics do this for you