Given a variadic template parameter pack, I want to check if all types given to it are unique using an inline constexpr bool
and fold expressions. I trie 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 doesn't compile regardless of what I put into is_one_of. Can this even be done using fold expressions, or do I need to use a regular struct for this purpose?
-- EDIT --
googling I've found an interesting solution that give me inspiration to avoid recursion and to avoid a lot of warnings
So you can define a wrapper of type
template <typename>
struct wrapT
{ };
and a wrapper for type and integer that inherit from the wrapper for type
template <typename T, std::size_t>
struct wrapTI : public wrapT<T>
{ };
Next you can define a foo
class that recursively inherit 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
can be something like
template <typename ... Ts>
static constexpr bool isUnique
= ( ... && std::is_convertible<foo<std::tuple<Ts...>>, wrapT<Ts>>::value );
The point is that foo<Ts...>
can be converted to wrapT<T>
only if foo<Ts...>
inherit one time (and only one time) from wrapT<T>
, that is if T
is present one time (and only one time) in Ts...
.
The following is a full compiling 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> );
}
You approach doesn't really work because is_one_of
needs to be called with a type T
and all the remaining types not including T
. There's no way of expressing that with a fold expression over a single parameter pack. I suggest using specialization instead:
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...>
>{};
Usage:
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 the simplification that uses a fold expression.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With