部分特化中模板模板参数内的可变参数模板参数

时间:2014-09-09 17:50:46

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

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

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<Operation_type,generic_set_element>然后我希望通用条件容器执行&#34;操作类型&#34; 选择的操作。 因此,如果将元素x与集合进行比较,则通用容器可以对x元素执行预先选择的操作。

2 个答案:

答案 0 :(得分:3)

你的编译器坏了。正确的错误消息如下所示(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 ...>’

或者这个(铿锵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;

无需重复参数两次。

答案 1 :(得分:1)

问题在于,您无法使用给定模板参数的 template-template参数专门化 template-template 参数,例如强制:

ContainerType<Args...>

匹配:

template <typename...> class BaseContainerType

因为它不再是模板模板参数。相反,此处需要使用普通的ContainerType名称,而不需要<Args...>部分:

// 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<T, A>这样的模板化容器专门设置它,这些容器只有两个参数:type T and allocator 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