Evaluate variational parameters from the virtual stack

I am creating a small byte based on the script bytecode to learn about the built-in scripts in C ++. The goal is to be able to register anyone std::functionto call the script. Now I have

class Bytecode
{
private:
Stack stack;

// Functions to be called from script.
// When a function is called, its arguments are expected to be in the stack.
std::vector<std::function<void(void)> > ops;

public:
// Register C++ function to be called by script
template<typename Func, typename T, typename... Args>
std::size_t function(Func fn, T arg, Args... args)
{
    // Substitute value from the stack to function parameter.
    auto fn2 = [fn,this](Args ...args) { fn(stack.pop().number, args...); };

    return function(fn2, args...);
}

template<typename Func, typename T>
std::size_t function(Func fn, T arg)
{
    std::function<void(void)> fn2 = [fn, this]() { fn(stack.pop().number); };

    return function(fn2);
}

template<typename Func>
std::size_t function(Func fn)
{
    ops.push_back(fn);

    // Return bytecode of the function (the same as ops index).
    return ops.size() - 1;
}
};

Then i can do

void myfunc(double a, double b)
{
    std::cout << a + b << std::endl;
}

int main()
{
Bytecode bytecode;

// The last two arguments are dummy
auto op = bytecode.function(myfunc, 3.4, 3.6);
}

So this works, but I would like to avoid providing dummy arguments. I tried to overload std::size_t function(std::function<void(T, Args...>) fn), but to no avail, because it seems that the specialized template arguments std::functiondo not work the same as regular template arguments. Any ideas?

Decision

In the end, I managed to get some kind of working solution in part through trial and error. Sorry the question was somewhat vague about the necessary use cases.

template<class T, class... Args>
std::size_t function(std::function<void(T,Args...)> &&fn)
{
    // Substitute value from the stack to function parameter.
    auto fn2 = [fn, this](Args ...args) { fn(stack.pop().as<T>(), std::forward<Args>(args)...); };

    return function(std::forward<std::function<void(Args...)> >(fn2));
}

std::size_t function(std::function<void(void)> &&fn)
{
    ops.push_back(fn);

    // Return bytecode of the function (the same as ops index).
    return ops.size() - 1;
}

,

void myfunc(double foo, int bar)
{
    std::cout << foo + bar << std::endl;
}

int main()
{
    Bytecode bytecode;

    auto op = bytecode.function(std::function<void(double,int)>(myfunc));
}

, std::function, , .

+4
1

std::function. ( ++ 14) std::function . ++ 17 ​​.

:

template<typename Func, std::size_t...Is>
std::size_t function(Func fn, std::index_sequence<Is...>) {
  std::function<void()> fn2 = [fn, this]() {
    // array guarantees left-to-right evaluation:
    double elems[] = { ( void(Is), stack.pop().number)... } // comma operator and init list
    fn( elems[Is]... );
  };
  ops.push_back(fn2);
  return ops.size()-1;
}
template<std::size_t N, typename Func>
std::size_t function(Func fn) {
  return function(fn, std::make_index_sequence<N>{});
}

:

auto op = bytecode.function<2>(myfunc);

, . , , , .

++ 14 . ++ 11 .

namespace notstd {
  template<std::size_T...Is>
  struct index_sequence {};

  template<std::size_t N, std::size_t...Is>
  struct make_index_sequence:
    make_index_sequence<N-1, N-1, Is...>
  {};
  template<std::size_t...Is>
  struct make_index_sequence<0, Is...>:
    index_sequence<Is...>
  {};
}

, , ++ 11.

+2

Source: https://habr.com/ru/post/1679573/


All Articles