我正在尝试使用可变参数模板将参数类型存储到成员函数中。我试图实现这一点的方法是将每个类型与一个键相关联,然后将该键存储在std :: vector中。创建此密钥的代码如下
template <typename T>
class ClassInfo {
public:
inline static void const* GetClassKey() {
static char key;
return &key;
}
};
然后我使用以下代码尝试将密钥存储在std :: vector
中class WrappedMemberFunction {
void *function_pointer; // Holds the member function pointer
void const* class_type; // Class type key
void const* return_type; // Return type key
std::vector<void const*> parameter_types; // Parameter type keys
void StoreArguments() {}
template <typename Arg, typename... Args>
void StoreArguments() {
parameter_types.push_back(ClassInfo<Arg>::GetClassKey());
StoreArguments<Args...>(); // Error here: No matching member function for call to 'StoreArguments'
}
public:
template <typename Class, typename ReturnType, typename... Args>
WrappedMemberFunction(ReturnType (Class::*member_pointer)(Args...)) {
// Store member pointer as regular old void pointer
function_pointer = (void*&)member_pointer;
// Store class type
class_type = ClassInfo<Class>::GetClassKey();
// Store return type
return_type = ClassInfo<Class>::GetClassKey();
// Store parameter types
StoreArguments<Args...>();
}
};
我所坚持的是存储每个类密钥所需的可变递归。我在上面指定的行上收到错误,这是尝试扩展参数包的递归步骤。我在这里做错了什么?
答案 0 :(得分:1)
你有:
// function that is not a template
void StoreArguments() {}
// function template that takes N+1 types
template <typename Arg, typename... Args>
void StoreArguments() {
parameter_types.push_back(ClassInfo<Arg>::GetClassKey());
// call function template that takes N types
StoreArguments<Args...>();
}
希望我添加的评论清楚地表明......你从一个功能模板中采用N + 1类型递归到一个采用N类型的函数模板。基本情况下有一个函数模板,它采用0种类型。你没有这个,你有一个不可或缺的功能 - 不会被考虑。
您的方法是将类型提升为值,因此您的基本案例 是一个无效的函数:
template <class T> struct tag { using type = T; };
void StoreArgumentsImpl() { }
template <typename Arg, typename... Tags>
void StoreArgumentsImpl(tag<Arg>, Tags... tags) {
parameter_types.push_back(ClassInfo<Arg>::GetClassKey());
StoreArgumentsImpl(tags...);
}
template <typename... Args>
void StoreArguments() {
StoreArgumentsImpl(tag<Args>{}...);
}
或者使用expander trick
在一个功能中执行所有操作template <typename... Args>
void StoreArguments() {
using expander = int[];
(void)expander{0,
(void(
parameter_types.push_back(ClassInfo<Args>::GetClassKey())
), 0)...
};
}
或者,在C ++ 17中(不能等待),使用折叠表达式:
template <typename... Args>
void StoreArguments() {
(parameter_types.push_back(ClassInfo<Args>::GetClassKey()), ...);
}
或者,在C ++ 17中,使用if constexpr(尽管这不适用于 no 参数):
template <typename Arg, typename... Args>
void StoreArguments() {
parameter_types.push_back(ClassInfo<Args>::GetClassKey());
if constexpr(sizeof...(Args) > 0) {
StoreArguments<Args...>();
}
}