通过转换可变模板参数来组成可变模板参数
Compose variadic template argument by transforming them
我有一个简单的情况,可能需要复杂的方法来解决,但我不确定。
基本上,我有一个封装了成员函数的对象:
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...);
}
};
这可以很容易地使用
MemberFunction<Foo, int, int, int> function(&Foo::add)
Foo foo;
int res = function.call(&foo, 10,20)
问题是,我想通过一个自定义环境来调用它,该环境使用一堆值来操作此方法,这转化为以下代码:
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));
这很容易直接在代码中完成,但我想找到一种方法,通过公开一个void call(Stack& stack)
方法,将这种行为直接封装到MemberFunction
类中,该方法为我获得以下内容:
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));
但是,由于我是一个新的可变模板,我不知道我如何才能做到高效和优雅。
编辑:添加有关Stack和StackValue的详细信息
我所说的堆栈是std::stack<StackValue>
的包装器,它提供了推送和弹出元素的模板方法,类似于
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;
}
}
为了保证以正确的顺序弹出内容,我们必须递归地执行此操作:
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);
不正确。这需要大量的右值引用。您要么想使用ARGS...
,要么将其作为一个函数模板来进行转发引用。此外,它可能应该返回R
。
相关文章:
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 如何将向量中的可变参数转换为参数的持有者?
- c++ 构造函数 将 1 个字符串参数转换为 3 个属性
- 将空*参数转换为各种类型的参数是UB吗?
- 将可变参数模板参数转换为 JSON 字符串
- C++ 如何将函数参数转换为字符串
- 功能指针参数参数转换为const
- 避免对模板运算符过载的隐式参数转换
- 将C 方法参数转换为模板参数会因编译错误而失败
- 将参数转换为lpwstr createProcess
- 在与时间一起使用 srand 时,如果我没有time_t参数明确地将参数转换为无符号的 int 参数,这有关系吗?
- 将C++整型模板参数转换为整型"longer"型
- 将参数转换为目标类型时,复制用于直接初始化的构造函数省略
- 将命令行参数转换为qimage
- 将可变数量的参数转换为明确的数量
- SDL 方法,参数转换
- 通过错误检查将参数转换为整数
- 功能参数转换为儿童类C
- 参数转换在课堂上
- 在窗口上将格式化的 C 字符串和参数转换为 wstring