Checking the uniqueness of the parameters of a variational template using flash expressions

Given the variable package of template parameters, I want to check if all types assigned to it are unique with the help of inline constexpr bool and short expressions . I am doing something like this:

 template<class... T> inline static constexpr bool is_unique = (... && (!is_one_of<T, ...>)); 

Where is_one_of is a similar bool that works correctly. But this line does not compile no matter what I inserted into is_one_of. Is it possible to do this even with the help of flash expressions or do I need to use a regular structure for this?

+5
source share
2 answers

You do not work because is_one_of must be called with type T and all other types , not including T It is not possible to express this using the fold expression on a single parameter package. Instead, I suggest using specialization:

 template <typename...> inline constexpr auto is_unique = std::true_type{}; template <typename T, typename... Rest> inline constexpr auto is_unique<T, Rest...> = std::bool_constant< (!std::is_same_v<T, Rest> && ...) && is_unique<Rest...> >{}; 

Using:

 static_assert(is_unique<>); static_assert(is_unique<int>); static_assert(is_unique<int, float, double>); static_assert(!is_unique<int, float, double, int>); 

live example on wandbox.org


(Thanks to Barry for simplification using the fold statement.)

+8
source

- 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> ); } 
+1
source

Source: https://habr.com/ru/post/1273682/


All Articles