c++ - 尝试扩展模板参数包时出错

标签 c++ templates

我正在尝试使用可变参数模板将参数类型存储到成员函数中。我试图实现这一点的方法是将每种类型与一个键相关联,然后将这个键存储在一个 std::vector 中。创建这个key的代码如下

template <typename T>
class ClassInfo {
public:
    inline static void const* GetClassKey() {
        static char key;
        return &key;
    }
};

然后我使用以下代码尝试将 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 种类型的函数模板。你没有那个,你有一个空函数 - 不会被考虑。

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

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

template <typename Arg, typename... Args>
void StoreArguments() {
    parameter_types.push_back(ClassInfo<Args>::GetClassKey());

    if constexpr(sizeof...(Args) > 0) {
        StoreArguments<Args...>();
    }
}

关于c++ - 尝试扩展模板参数包时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38491250/

相关文章:

c++ - 将统一内存指针传递给内核会减慢程序速度

templates - 如何用 hamlet 打印逗号分隔的列表?

c++ - 如何在编译时检测基类的模板参数(错误)?

c++ - 可变参数模板 : unfold arguments in groups

c++ - 模板类中非模板成员函数的 requires 子句

c++ - 具有不同对齐要求的不同类型的两个对象可以具有相同的对象表示吗?

c++ - 我在 C++ 草稿 GitHub 中找不到问题或拉取请求,支持 [basic.start.static]/2 中的以下更改

c++ - 为什么我们不能使用两个不同的可互换枚举?作为函数参数?

c++ - itoa 到 std::to_string

c++ - 如何将函数应用于可变参数列表并将它们分类为元组