Compose the variational argument of the template by converting them

I have a simple situation that probably requires a difficult way to solve, but I'm not sure about that.

I basically have this object that encapsulated a member function:

template<class T, typename R, typename... ARGS>
class MemberFunction
{
private:
  using function_type = R (T::*)(ARGS...);

  function_type function;

public:
  MemberFunction(function_type function) : function(function) { }

  void call(T* object, ARGS&&... args)
  {
    (object->*function)(args...);
  }   
};

It can be used easily.

MemberFunction<Foo, int, int, int> function(&Foo::add)
Foo foo;
int res = function.call(&foo, 10,20)

The problem is that I would like to call it, going through a custom environment that uses a value stack to control this method, this translates to the following code:

int arg2 = stack.pop().as<int>();
int arg1 = stack.pop().as<int>();
Foo* object = stack.pop().as<Foo*>();
int ret = function.call(object, arg1, arg2);
stack.push(Value(int));

This is easy to do directly in the code, but I would like to find a way to encapsulate this behavior directly in the class MemberFunction, exposing one method void call(Stack& stack)that does the work for me to get something like:

MemberFunction<Foo, int, int, int> function(&Foo::add);
Stack stack;
stack.push(Value(new Foo());
stack.push(10);
stack.push(20);
function.call(stack);
assert(stack.pop().as<int>() == Foo{}.add(10,20));

But since I'm new to variable templates, I don't know how I could do this efficiently and elegantly.

EDIT: Stack StackValue

, , std::stack<StackValue>, push pop , -

struct StackValue
{
  union
  {
    float fvalue;
    s32 ivalue;
    bool bvalue;
    FloatPair fpair;
    IntPair ipair;
    void* ptr;
  };

  template<typename T> T as();
  template<typename T> StackValue(T type);

  StackValue() { }
};

template<> inline StackValue::StackValue(float f) : fvalue(f) { }
template<> inline StackValue::StackValue(s32 i) : ivalue(i) { }
...

template<> inline float StackValue::as<float>() { return fvalue; }
template<> inline s32 StackValue::as<s32>() { return ivalue; }
...

class Stack
{
private:
  std::stack<StackValue> stack;

public:
  StackValue& peek() { return stack.top(); }
  StackValue pop() { StackValue v = stack.top(); stack.pop(); return v; }
  void push(StackValue value) { stack.push(value); }

  template<typename T> void pushValue(T value) { stack.push(StackValue(value)); }
  template<typename T> T popValue() {
      StackValue v = stack.top().as<T>();
      stack.pop();
      return v;
  }
}
+4
1

, , - :

void call(Stack& s) {
    call_impl(std::integral_constant<int, sizeof...(ARGS)>{}, s);
}

:

template <int N, typename... StackVals>
void call_impl(std::integral_constant<int, N>, Stack& s, StackVals... vals) {
    call_impl(std::integral_constant<int, N-1>{}, s, s.pop(), vals...);
}

template <typename... StackVals
void call_impl(std::integral_constant<int, 0>,
               Stack& s,
               StackVals... vals)
{
    // now we have all the args
    T* object = s.pop().as<T*>();

    // so just call
    s.push(call(object, vals.as<Args>()...));
}

-, pop , pop() -ed . :

vals.as<Args>()...

vals - StackValues, , Args . , ( ). :

val0.as<Arg0>, val1.as<Arg1>, val2.as<Arg2>, ...

. , , T* call().


, :

void call(T* object, ARGS&&... args);

. rvalue. ARGS..., . , , R.

+4

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


All Articles