Search code examples
c++tuplesmetaprogramming

How to filter duplicate types from tuple C++


How does one filter duplicate types from a tuple?

For example:

using Tuple = std::tuple<int, double, int, double, std::string, std::string>
using FilteredTuple = without_duplicates<Tuple>;

In which without_duplicates is implemented in such a way that it generates the following FilteredTuple type:

std::tuple<int, double, std::string>

Solution

  • This should work:

    template <class Haystack, class Needle>
    struct contains;
    
    template <class Car, class... Cdr, class Needle>
    struct contains<std::tuple<Car, Cdr...>, Needle> : contains<std::tuple<Cdr...>, Needle>
    {};
    
    template <class... Cdr, class Needle>
    struct contains<std::tuple<Needle, Cdr...>, Needle> : std::true_type
    {};
    
    template <class Needle>
    struct contains<std::tuple<>, Needle> : std::false_type
    {};
    
    
    
    template <class Out, class In>
    struct filter;
    
    template <class... Out, class InCar, class... InCdr>
    struct filter<std::tuple<Out...>, std::tuple<InCar, InCdr...>>
    {
      using type = typename std::conditional<
        contains<std::tuple<Out...>, InCar>::value
        , typename filter<std::tuple<Out...>, std::tuple<InCdr...>>::type
        , typename filter<std::tuple<Out..., InCar>, std::tuple<InCdr...>>::type
      >::type;
    };
    
    template <class Out>
    struct filter<Out, std::tuple<>>
    {
      using type = Out;
    };
    
    
    template <class T>
    using without_duplicates = typename filter<std::tuple<>, T>::type;
    

    [Live example]

    [Godbolt]

    It works by iteratively constructing the output tuple. Before each type is added, check (using the predicate contains) whether it's already in the output tuple or not. If not, it's added (the "else" branch of std::conditional), otherwise it's not added (the "then" branch of std::conditional).