尝试展开模板参数包时出错

Error when trying to expand template parameter pack

本文关键字:参数 包时 出错      更新时间:2023-10-16

我正在尝试使用可变模板将参数类型存储到成员函数中。我试图实现这一点的方法是将每个类型与一个键关联起来,然后将这个键存储在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...>();
    }
};

我一直纠结于存储每个类键所需的可变递归。我在上面指出的行中得到一个错误,这是试图扩展参数包的递归步骤。我在这里做错了什么?

您有:

// 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类型的函数模板。你没有,你有一个空函数——这不会被考虑。

您的方法是将类型提升为值,因此您的基本情况实际上一个null函数:

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>{}...);
}

或者使用扩展器技巧在单个函数中完成所有操作:

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(尽管这不适用于参数):

template <typename Arg, typename... Args>
void StoreArguments() {
    parameter_types.push_back(ClassInfo<Args>::GetClassKey());
    if constexpr(sizeof...(Args) > 0) {
        StoreArguments<Args...>();
    }
}