确保可变参数模板不包含重复项

时间:2015-12-06 20:14:47

标签: c++ templates c++11 variadic-templates

我想我的整个问题在标题中有详细描述。我正在尝试创建一个可变的类模板(在C ++ 11,C ++ 14或C ++ 1z中)。

template<typename ...Types> struct MyVariadicTemplate {};

并确保MyVariadicTemplate的任何实例化中的类型列表都是单射的,因此,例如,如果我调用以下代码:

MyVariadicTemplate<int, double, int> x;

它不会编译(我很乐意使用static_assert以某种方式这样做。)

我会很感激。

3 个答案:

答案 0 :(得分:4)

这可以在两个元函数的帮助下编写。

首先,IsContained检查类型是否出现在类型列表中。

template <typename T, typename... List>
struct IsContained;

template <typename T, typename Head, typename... Tail>
struct IsContained<T, Head, Tail...>
{
    enum { value = std::is_same<T, Head>::value || IsContained<T, Tail...>::value };
};

template <typename T>
struct IsContained<T>
{
    enum { value = false };
};

其次,IsUnique检查类型列表是否不包含重复项。它使用IsContained来检查所有元素组合。

template <typename... List>
struct IsUnique;

template <typename Head, typename... Tail>
struct IsUnique<Head, Tail...>
{
    enum { value = !IsContained<Head, Tail...>::value && IsUnique<Tail...>::value };
};

template <>
struct IsUnique<>
{
    enum { value = true };
};

使用这些工具,静态断言非常简单:

template <typename... Ts>
struct NoDuplicates
{
    static_assert(IsUnique<Ts...>::value, "No duplicate types allowed");
};

答案 1 :(得分:2)

如果您可以访问C ++ 1z折叠表达式,则可以通过对IsContained执行以下操作来简化@ TheOperator的答案:

template <typename T, typename... List>
struct IsContained;

template <typename T, typename Head, typename... Tail>
struct IsContained<T, Head, Tail...>
{
    enum { value = std::is_same<T, Head>::value || (IsContained<T, Tail>::value && ... && true) };
};

template <typename T>
struct IsContained<T>
{
    enum { value = false };
};

不同之处在于,使用fold表达式重新使用类实例化的可能性更大。如果您使用了大量参数或进行了多次重复比较,则可能的编译时间更短。一如既往,亲自测试一下。

答案 2 :(得分:0)

使用 c++17 这很容易。

#include <type_traits>

template <typename T, typename... Ts>
struct are_distinct: std::conjunction<
    std::negation<std::is_same<T, Ts>>...,
    are_distinct<Ts...>
>{};

template <typename T>
struct are_distinct<T>: std::true_type{};

该算法与 JkorTheOperator 所示的算法相同,但表达得更加简洁。

然后,针对您的具体问题,您可以这样使用它:

template<typename ...Types> 
struct MyVariadicTemplate {
    static_assert(are_distinct<Types...>::value, "Types must be distinct");

    /* rest of the code */
};

然而,鉴于这是 O(n²),我想知道是否有办法让它在算法上不那么复杂? Boost::mpl's unique<> is O(n),但我无法理解它使用的算法。