3

I have the following code to check the uniqueness of template parameters:

template <typename ...Tn>
struct uniq_types 
{
    static constexpr const bool value = true;
};

template <typename T1, typename T2, typename ...Tn>
struct uniq_types<T1, T2, Tn...> 
{
    static constexpr const bool value
        = !std::is_same<T1, T2>::value && uniq_types<T1, Tn...>::value && uniq_types<T2, Tn...>::value;
};

template <typename T>
struct uniq_types<T> 
{
    static constexpr const bool value = true;
};

It works fine. But then, if I want to check the uniqueness of the template parameters of a container, std::tuple for example, I need to partially specialize it like:

template <typename ...Tn>
struct uniq_types<std::tuple<Tn...>> : public uniq_types<Tn...> 
{
};

I wonder whether there is a way to do so without partial specialization for every container.

I have tried

template <template <typename...> typename U, typename... Tn>
struct unique_types;

template <template <typename T1, typename T2, typename... Tn> typename U,
                    typename T1, typename T2, typename... Tn>
struct unique_types<U, T1, T2, Tn...> 
{
    static constexpr const bool value 
        = !std::is_same<T1, T2>::value && unique_types<U, T1, Tn...>::value && unique_types<U, T2, Tn...>::value;
};

template <template <typename T> typename U, typename T>
struct unique_types<U, T> 
{
    static constexpr const bool value = true;
};

It works, but then to check, I have to "expand" the template parameters of the container like this:

unique_types<std::tuple, int>::value

I would like to do something like this:

unique_types<std::tuple<int>>::value; // true
unique_types<std::tuple<int, double>>::value; // true
unique_types<std::tuple<int, double, int>>::value; // false
HCSF
  • 2,387
  • 1
  • 14
  • 40

3 Answers3

1

You can make the traits to specialise for the template template parameters. Then using std::conjunction you can do this

#include <type_traits> // std::is_same, std::conjunction_v

template<typename Type, typename... Rs>
constexpr bool areSameTypes = std::conjunction_v<std::is_same<Type, Rs>...>;

template <typename T>
struct unique_types : std::false_type {};

template <template<typename...> class Container, typename... V>
struct unique_types<Container<V...>>
{
   constexpr static bool value = areSameTypes<V...>;
};

Now you could

static_assert(unique_types<std::tuple<int>>::value, "not unique");
static_assert(unique_types<std::tuple<int, int, int>>::value, "not unique");
// static_assert(unique_types<std::tuple<int, char, int>>::value, "not unique");  // error

See a demo

JeJo
  • 30,635
  • 6
  • 49
  • 88
  • Thanks. My question probably wasn't too clear -- I was actually asking for checking whether types of all template template parameters are unique. Your solution checks whether all have the same types. +1 for pointing out `std::conjunction_v`. – HCSF Jul 31 '20 at 02:34
  • I think I can just modify your solution with `std::negation` in front of `std::is_same`. – HCSF Jul 31 '20 at 02:42
  • actually, I think even with `std::negation`, it won't work. For instance, gcc and clang 10.0 compiles `static_assert(unique_types>::value)` without an error. I think the problem is that `std::conjunction_v>...>` is compiled into `!std::is_same::value> && `!std::is_same::value> && `!std::is_same::value>`...so it does not create a conjunction of permutation of all types with `std::same`. – HCSF Aug 02 '20 at 12:45
0

There is the std::type_index wrapper around std::type_info which is a data type returned from typeid() operator. It will index types for the lifetime of the program afaik.

std::type_index(typeid(T));

https://en.cppreference.com/w/cpp/language/typeid

https://en.cppreference.com/w/cpp/types/type_index

Tittyfish
  • 1
  • 1
0

I ended up with something like this

#include <tuple>
#include <type_traits>

template <typename ...Tn>
struct uniq_types 
{
    static constexpr const bool value = true;
};

template <typename T1, typename T2, typename ...Tn>
struct uniq_types<T1, T2, Tn...> 
{
    static constexpr const bool value
        = !std::is_same<T1, T2>::value && uniq_types<T1, Tn...>::value && uniq_types<T2, Tn...>::value;
};

template <typename T>
struct uniq_types<T> 
{
    static constexpr const bool value = true;
};

template <typename T>
struct unique_types : uniq_types<T> {
    static constexpr const bool value = uniq_types<T>::value;
};

template <template <typename...> typename C, typename... Tn>
struct unique_types<C<Tn...>> {
    static constexpr const bool value = uniq_types<Tn...>::value;
};

int main() {
    static_assert(unique_types<std::tuple<int>>::value); // okay
    static_assert(unique_types<std::tuple<int, bool, bool, char>>::value); // error
}
HCSF
  • 2,387
  • 1
  • 14
  • 40