سؤال

Suppose I have some functions written and compiled in C++:

int quicksum(int a, int b){ return a+b; }
int quickmult(int a, int b){ return a*b; }

At runtime, I'd like to be able to create a combination of these functions, such as quicksum(quickmult(5,6),7) and keep that around as a saved procedure that I could execute any time.

Currently, I'm getting halfway there by using JavaScript and C++ together in Qt, where functions like quicksum are defined in C++, and then invoked from JavaScript by doing this:

    var somestring="quicksum(5,(quicksum(4,4)))"
    eval(somestring)

Now that works, but the problem is that the combination of these functions is still being managed on the JavaScript side, which means that JS is handling the return from one function before inputting it into another function, rather than C++ running the entire combination itself (at least I assume that to be the case).

I don't mind creating the initial combination in JS but for performance reasons I don't want JS involved every time I need to call the combination of functions.

Is there a way to somehow get this combination of functions into the C++ side and have it stay there for running later? I don't mind taking JS out of the process entirely, it's just the only method I could think of; perhaps there is some clever way of using functors in C++ for dynamically stitching together functions at runtime that have been previously compiled?

Update...

Another option I am considering is to use functors that themselves have member variables that refer to other functors. This would be a bit like creating a new function with a closure at runtime if the JS called a functor constructor with parameters of other functors. Then this functor would entirely be a C++ object with the procedure stored within (I think). I will need to work this out in my head for a bit.

هل كانت مفيدة؟

المحلول

Evaluating a run-time constructed function is not going to be “quick” in any reasonable sense of the word, unless you go full out and compile it, e.g. to a dynamic library.

Barring that you can just construct a dynamic expression tree.

You will probably want to add a bit of syntactic sugar compared to the code below, but it shows the basics:

#include <iostream>
#include <functional>   // std::plus, std::multiplies
#include <memory>       // std::unique_ptr
#include <utility>      // std::move
using namespace std;

struct Expression
{
    virtual auto eval() const -> double = 0;
    virtual ~Expression() {}
};

struct Number: Expression
{
    double      value;

    auto eval() const -> double override { return value; }

    Number( double v ): value( v ) {}
};

struct Binary_op: Expression
{
    unique_ptr<Expression>  a;
    unique_ptr<Expression>  b;

    Binary_op( unique_ptr<Expression> _a, unique_ptr<Expression> _b )
        : a( move( _a ) ), b( move( _b ) )
    {}
};

template< class Impl >
struct Concrete_binary_op: Binary_op
{
    auto eval() const -> double override
    { return Impl()( a->eval(), b->eval() ); }

    Concrete_binary_op( unique_ptr<Expression> _a, unique_ptr<Expression> _b )
        : Binary_op( move( _a ), move( _b ) )
    {}
};

using Sum       = Concrete_binary_op<std::plus<double>>;
using Product   = Concrete_binary_op<std::multiplies<double>>;

auto number( double v )
    -> unique_ptr<Number>
{ return unique_ptr<Number>( new Number( v ) ); }

auto sum( unique_ptr<Expression> a, unique_ptr<Expression> b )
    -> unique_ptr<Sum>
{ return unique_ptr<Sum>( new Sum( move( a ), move( b ) ) ); }

auto product( unique_ptr<Expression> a, unique_ptr<Expression> b )
    -> unique_ptr<Product>
{ return unique_ptr<Product>( new Product( move( a ), move( b ) ) ); }

auto main()
    -> int
{
    auto e = sum( product( number( 5 ), number( 6 ) ), number( 7 ) );
    cout << e->eval() << endl;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top