How to filter duplicate types from tuple C++

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).


#include <type_traits>
#include <tuple>

template <typename T, typename... Ts>
struct unique : std::type_identity<T> {};

template <typename... Ts, typename U, typename... Us>
struct unique<std::tuple<Ts...>, U, Us...>
    : std::conditional_t<(std::is_same_v<U, Ts> || ...)
                       , unique<std::tuple<Ts...>, Us...>
                       , unique<std::tuple<Ts..., U>, Us...>> {};

template <typename... Ts>
using unique_tuple = typename unique<std::tuple<>, Ts...>::type;

DEMO