This is a code snippet that I am going to use in order to check whether the variadic template types are unique:
template
struct is_one_of
#include <type_traits>
template <typename F, typename... Ts>
constexpr bool is_one_of = (std::is_same<F, Ts>{} || ...);
template <typename...>
constexpr bool is_unique = true;
template <typename F, typename... Ts>
constexpr bool is_unique<F, Ts...> = is_unique<Ts...> && !is_one_of<F, Ts...>;
DEMO
I'd (now) suggest using the std::conj/disj/nega
family of STL functions:
#include <type_traits>
template <typename H, typename... T>
struct is_one_of : std::disjunction<std::is_same<H, T>...> {};
template <typename H, typename... T>
struct is_unique : std::conjunction<std::negation<std::is_same<H, T>>..., is_unique<T...>> {};
template <typename H>
struct is_unique<H> : std::true_type {};
int main()
{
static_assert(is_one_of<int, char, double, int, bool>::value);
static_assert(is_unique<int, char, double, bool>::value);
static_assert(!is_unique<int, int, char, double, bool>::value);
}
When fold-expressions, which were designed for these cases, are released into the language this will become trivial:
namespace stx = std::experimental;
template <typename H, typename... T>
struct is_one_of {
static constexpr bool value = (stx::is_same_v<H, T> || ...);
};
template <typename H, typename... T>
struct is_unique {
static constexpr bool value = (!stx::is_same_v<H, T> && ... && is_unique<T...>::value);
};
template <typename H>
struct is_unique<H> : std::true_type {};
We recently added std::disjunction to the C++1z draft, which can be used for is_one_of
(and it stops instantiating as soon as it finds a match, see the link for more details):
template <typename F, typename... T>
using is_one_of = std::disjunction<is_same<F, T>...>;
This is already implemented in GCC trunk. For older versions of GCC you can use the implementation detail __or_
instead:
template <typename F, typename... T>
using is_one_of = std::__or_<is_same<F, T>...>;
Or implement disjunction
by hand using C++11 facilities, as shown at the end of the proposal linked to above.
I'm in line with Brian Rodriguez's and Piotr Scontnincki's answers, as far as it concerns the fold expressions part. Until folding expressions are in, you could shrink the existing code a little bit by getting rid of the incomplete primary templates as follows:
template <typename...>
struct is_one_of {
static constexpr bool value = false;
};
template <typename F, typename S, typename... T>
struct is_one_of<F, S, T...> {
static constexpr bool value =
std::is_same<F, S>::value || is_one_of<F, T...>::value;
};
template <typename...>
struct is_unique {
static constexpr bool value = true;
};
template <typename F, typename... T>
struct is_unique<F, T...> {
static constexpr bool value = is_unique<T...>::value && !is_one_of<F, T...>::value;
};