首页 > 解决方案 > 模板参数提取和修改

问题描述

我编写了以下类来提取类的模板参数并在编译时Base将类的模板参数附加到它:Derived

template <typename...> struct derived_type_traits;

// specialization for the case when Base is not a template
template <typename Base> struct derived_type_traits<Base> {
    template <template<typename...> class Derived, typename... DerivedArgs>
    using type = Derived<DerivedArgs...>;
};

// specialization for the case when Base is a template
template <template <typename...> class Base, typename... BaseArgs> struct derived_type_traits<Base<BaseArgs...>> {
    template <template<typename...> class Derived, typename... DerivedArgs>
    using type = Derived<DerivedArgs..., BaseArgs...>;
};

我将它用作工厂构建模块的一部分。使用这个特征类,我可以Derived从一组模板参数和一个Base类中构造一个:

namespace A {
    class Base {};
    template <typename T>
    class Derived : public Base {};
    auto ptr = new typename derived_type_traits<Base>::type<Derived, int>();
}

namespace B {
    class Base {};
    template <typename T1, typename T2, typename T3>
    class Derived : public Base {};
    auto ptr = new typename derived_type_traits<Base>::type<Derived, int, double, std::string>();    
}

namespace C {
    template <typename T>
    class Base {};
    template <typename T1, typename T2, typename T3, typename T>
    class Derived : public Base<T> {};
    auto ptr = new typename derived_type_traits<Base<int>>::type<Derived, int, double, std::string>();  
}

但是,它不适用于以下情况:

namespace D {
    template <typename T>
    class Base {};
    template <typename T1, typename T2, template <typename,typename> class T3, typename T>
    class Derived : public Base<T> {};
    template <typename T1, typename T2> struct Foo {};
    auto ptr = new typename derived_type_traits<Base<int>>::type<Derived, int, double, Foo>();
}

namespace E {
    template <typename U1, template <typename,typename> class U2>
    class Base {};
    template <typename T1, typename T2, typename T3, typename U1, template<typename,typename> class U2>
    class Derived : public Base<U1,U2> {};
    template <typename T1, typename T2> struct Foo {};
    auto ptr = new typename derived_type_traits<Base<int, Foo>>::type<Derived, int, double, std::string>();
}

测试代码在这里

我知道这与可变参数模板无法匹配类型和模板类型的混合这一事实有关。

有解决方案还是我走错路了?我最多可以使用 C++14(没有 C++17)。

标签: c++c++14variadic-templatestemplate-meta-programmingtypetraits

解决方案


您是元元编程,而 C++ 并不真正支持这一点。这也是一个值得商榷的计划,有点像三星级节目。

如果你想元元编程,你将不得不限制你的元编程更加统一。把一切都变成类型。

使用std::integral_constant类型来传递值(甚至适用于函数指针!)。利用

template<template<class...>class Z>struct ztemplate

传递模板。

或者(或另外)转向基于价值的元编程。将类型作为值传递template<class>struct tag_t,模板被替换为从标签映射到标签的对象或函数等。

这两种方法都允许在更高程度上更容易和更简单的递归元编程。

在原始 C++ TMP 中执行此操作会遇到这个问题,还有一堆烦人的规则最终会让你失望(比如将包传递给 1 个参数模板)和平庸的编译器支持。

最后,请注意,在您的具体情况下:

template <typename T1, typename T2, typename T3, typename U1, template<typename,typename> class U2>
class Derived : public Base<U1,U2> {};

比:

template <typename T1, typename T2, typename T3, class Base>
class Derived : public Base {};
auto ptr = new Derived< int, double, std::string, Base<int, Foo>>();

推荐阅读