Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ensuring that a variadic template contains no duplicates

I guess my whole problem is well described in the title. I am trying to create a variadic class template (in C++11, C++14 or C++1z).

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

and make sure that the list of types in any instantiation of MyVariadicTemplate is injective, so if I, for instance, call the following piece of code:

MyVariadicTemplate<int, double, int> x;

it won't compile (I'd be happy to do that somehow using static_assert).

I would appreciate a hint.

like image 594
Jytug Avatar asked Oct 20 '25 14:10

Jytug


2 Answers

This can be written with the help of two metafunctions.

First, IsContained checks whether a type appears in a type list.

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 };
};

Second, IsUnique checks whether a type list contains no duplicates. It uses IsContained to check all element combinations.

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 };
};

With these tools, the static assertion is then very simple:

template <typename... Ts>
struct NoDuplicates
{
    static_assert(IsUnique<Ts...>::value, "No duplicate types allowed");
};
like image 124
TheOperator Avatar answered Oct 23 '25 04:10

TheOperator


If you have access to C++1z fold expressions, you can simplify @TheOperator's answer by doing the following for 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 && ... && true) };
};

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

The difference is that with the fold expression there is a larger chance of re-use of the class instantiations. If you are using a lot of parameters or have many repeat comparisons, this might have a faster compilation time. As always, test it out yourself.

like image 21
JKor Avatar answered Oct 23 '25 04:10

JKor



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!