【问题标题】:Variadic template argument within template template parameter in a partial specialization部分特化中的模板模板参数中的可变模板参数
【发布时间】:2014-09-09 17:50:45
【问题描述】:

我正在尝试开发一个通用代码,它可以选择不同的容器类型(std::vectorstd::map、其他),并对该容器包装器执行操作,但我遇到了以下代码:

enum class EContainnerType
{
    EContainnerType_Normal,
    EContainnerType_OR,
    EContainnerType_AND
};

// Base declaration
template<EContainnerType, template<class ... > class ContainerType, class ... ArgType >
struct ConditionContainnerType
{
};

// Partial Specialization    
template< template<class ... > class ContainerType, class ... ArgType >
struct ConditionContainnerType<EContainnerType::EContainnerType_OR, ContainerType<ArgType ... >, ArgType ...>
{
};   

int main()
{
    return 0;
}

可变参数模板模板参数没有编译,我得到这个错误:

main.cpp:33:108: error: wrong number of template arguments (2, should be 3)
 struct ConditionContainnerType<EContainnerType::EContainnerType_OR,typename ContainerType<ArgType>, ArgType>
                                                                                                            ^

main.cpp:29:8: error: provided for 'template<EContainnerType <anonymous>, template<class> class ContainerType, class ArgType> struct ConditionContainnerType'
 struct ConditionContainnerType

目标:

此实现的主要目标是执行某种分类操作(OR、AND、XOR),此操作是在与通用容器进行比较的元素上执行的。

操作类型由enum class定义,选择部分特化来做操作。

所以,如果我有一个集合 {a,b,c,d,e} 并且我用特定的元素组合填充集合,请说: generic_container&lt;Operation_type,generic_set_element&gt; 然后我希望通用条件容器执行 “操作类型” 选择的操作。 因此,如果将元素 x 与集合进行比较,通用容器可以对 x 元素执行预选操作。

【问题讨论】:

  • 似乎您可能以错误的方式处理此问题。为什么像标准算法那样处理迭代器对的方法不适合您?告诉我们您想要完成什么,而不是您尝试如何完成它。
  • ContainerType 模板参数可能会被单个 typename 替换。如果传递了错误的类型,在使用不存在的类型成员时会出现编译器错误。
  • 关于来自 Dark Falcon 的评论,你可以去read about the XY problem
  • 也可能想了解std::accumulate。我相信它已经可以为你做到这一点了。

标签: c++ templates variadic-templates template-specialization


【解决方案1】:

你的编译器坏了。正确的错误信息如下所示(g++ 4.8.2)

error: type/value mismatch at argument 2 in template parameter list for ‘template<EContainnerType <anonymous>, template<class ...> class ContainerType, class ... ArgType> struct ConditionContainnerType’
struct ConditionContainnerType<EContainnerType::EContainnerType_OR,ContainerType<ArgType ... >,ArgType ...>
                                                                                                             ^
error:   expected a class template, got ‘ContainerType<ArgType ...>’

或者这个(clang 3.3)

error: template argument for template template parameter must be a class template or type alias template
struct ConditionContainnerType<EContainnerType::EContainnerType_OR,ContainerType<ArgType ... >,ArgType ...>
                                                                     ^

它们是不言自明的。

所以只需删除参数。

//Partial Specialization

template< template<class ... > class ContainerType, class ... ArgType >
struct ConditionContainnerType<EContainnerType::EContainnerType_OR,
  ContainerType, ArgType ...>
{
};   

现在你可以写了

ConditionContainnerType<EContainnerType::EContainnerType_OR, std::vector, int> a;
ConditionContainnerType<EContainnerType::EContainnerType_OR, std::map, int, int> b;

无需重复两次参数。

【讨论】:

    【解决方案2】:

    问题是您不能使用具有给定模板参数的 模板模板参数来专门化 模板模板 参数,例如强制:

    ContainerType<Args...>
    

    匹配:

    template <typename...> class BaseContainerType
    

    因为它不再是模板模板参数。相反,这里需要使用纯 ContainerType 名称,没有 &lt;Args...&gt; 部分:

    // Base declaration
    template <template <typename...> class ContainerType>
    struct ConditionContainnerType
    {
    };
    
    // Partial specialization for two-parameter template template parameter
    template <template <typename, typename> class ContainerType>
    struct ConditionContainnerType<ContainerType>
    {
    };  
    

    但是,您可以使用填充参数的 template-template 参数(甚至使用扩展的参数包)来专门化模板类型本身,如下所示:

    // Base declaration
    template <EContainnerType, typename ContainerType, typename... Args>
    //                         ^^^^^^^^^^^^^^^^^^^^^^^ normal type here
    struct ConditionContainnerType
    {
    };
    
    // Partial specialization
    template <template <typename...> class ContainerType, typename... Args>
    //        ^^^^^^^^ template here
    struct ConditionContainnerType<EContainnerType::EContainnerType_OR,
                                   ContainerType<Args...>,
    //                                           ^^^^^^^ expanded parameter pack
                                   Args...>
    {
    };  
    

    或没有尾随参数包:

    template <template <typename...> class ContainerType, typename... Args>
    struct ConditionContainnerType<EContainnerType::EContainnerType_OR,
                                   ContainerType<Args...>>
    {
    };  
    

    以及将其专门用于模板化容器,例如 std::vector&lt;T, A&gt;,它只需要两个参数:类型 T 和分配器 A

    template <template <typename, typename> class ContainerType, typename T, typename A>
    struct ConditionContainnerType<EContainnerType::EContainnerType_OR,
                                   ContainerType<T, A>,
                                   T>
    {
    };  
    

    测试:

    int main()
    {
        // base, AND does not match OR
        ConditionContainnerType<EContainnerType::EContainnerType_AND
                               , MyContainer<int>
                               , int>{};
    
        // specialized, OR and parameter pack matches
        ConditionContainnerType<EContainnerType::EContainnerType_OR
                               , MyContainer<int>
                               , int>{};
    
        // base, OR matches, but parameters packs do not
        ConditionContainnerType<EContainnerType::EContainnerType_OR
                               , MyContainer<float>
                               , int>{};
    
        // vector, OR and parameter pack matches
        ConditionContainnerType<EContainnerType::EContainnerType_OR
                               , std::vector<int>
                               , int>{};
    
        // OR and no parameter-pack
        ConditionContainnerType<EContainnerType::EContainnerType_OR
                               , std::vector<int>>{};
    }
    

    DEMO


    如果您的目标是根据具体容器类型(std::vectorstd::map)专门化您的基本声明,则可以按以下方式执行此操作:

    // Base declaration
    template <EContainnerType, template <typename...> class ContainerType>
    struct ConditionContainnerType
    {
    };
    
    // Partial specialization for std::vector
    template <>
    struct ConditionContainnerType<EContainnerType::EContainnerType_OR, std::vector>
    //                                                                  ^^^^^^^^^^^
    {
    };
    
    // Partial specialization for std::map
    template <>
    struct ConditionContainnerType<EContainnerType::EContainnerType_AND, std::map>
    //                                                                   ^^^^^^^^
    {
    };  
    

    测试:

    int main()
    {
        // First specialization
        ConditionContainnerType<EContainnerType::EContainnerType_OR, std::vector>{};
    
        // Second specialization
        ConditionContainnerType<EContainnerType::EContainnerType_AND, std::map>{};
    }
    

    DEMO 2

    【讨论】:

      猜你喜欢
      • 2017-10-15
      • 2012-01-14
      • 1970-01-01
      • 2023-03-13
      • 2015-02-19
      • 2013-09-14
      • 1970-01-01
      • 2018-07-31
      • 1970-01-01
      相关资源
      最近更新 更多