- EDIT -
googling I found an interesting solution that inspires me to avoid recursion and avoid many warnings
So you can define a shell like
template <typename> struct wrapT { };
and a wrapper for the type and integer that inherit from the shell for the type
template <typename T, std::size_t> struct wrapTI : public wrapT<T> { };
Next, you can define a class foo that recursively inherits from wrapTI
template <typename T, typename = std::make_index_sequence<std::tuple_size<T>::value>> struct foo; template <typename ... Ts, std::size_t ... Is> struct foo<std::tuple<Ts...>, std::index_sequence<Is...>> : public wrapTI<Ts, Is>... { };
Now is_unique might be something like
template <typename ... Ts> static constexpr bool isUnique = ( ... && std::is_convertible<foo<std::tuple<Ts...>>, wrapT<Ts>>::value );
The fact is that foo<Ts...> can be converted to wrapT<T> only if foo<Ts...> inherits once (and only once) from wrapT<T> , that is, if T present one times (and only one time) in Ts...
Below is a complete compilation example
#include <tuple> #include <type_traits> template <typename> struct wrapT { }; template <typename T, std::size_t> struct wrapTI : public wrapT<T> { }; template <typename T, typename = std::make_index_sequence<std::tuple_size<T>::value>> struct foo; template <typename ... Ts, std::size_t ... Is> struct foo<std::tuple<Ts...>, std::index_sequence<Is...>> : public wrapTI<Ts, Is>... { }; template <typename ... Ts> static constexpr bool isUnique = ( ... && std::is_convertible<foo<std::tuple<Ts...>>, wrapT<Ts>>::value ); int main () { static_assert( true == isUnique<int, long, long long> ); static_assert( false == isUnique<int, long, long long, int> ); }