I need a template to find out the order of types in which the class inherits from its bases and their index. The code works fine with clang and gcc but in Visual Studio, which is the target environment, I'm getting an internal compiler error "fatal error C1001: An internal error has occurred in the compiler.". I'm looking for some workaround or maybe an error in my code. Yes, I have already tried google.
Thanks, in advance.
#include <type_traits>
#include <iostream>
struct BaseA
{
};
struct BaseB
{
};
struct BaseC
{
};
template <class... Types>
class type_list {};
template<typename Type, typename TypeList>
struct get_idx_for_type;
template<typename Type, template<typename...> typename TypeList, typename ...Types>
struct get_idx_for_type<Type, TypeList<Types...>>
{
template<int I, typename T, typename ...Rest>
struct find_type;
template<int I, typename T, typename U, typename ...Rest>
struct find_type< I, T, U, Rest... >
{
// problematic line for compiler, problem is somewhere in find_type recursion
static constexpr int value = std::is_same<T, U>::value ? I : find_type<I + 1, T, Rest...>::value;
};
template<int I, typename T, typename U>
struct find_type< I, T, U >
{
static constexpr int value = std::is_same<T, U>::value ? I : -1;
};
static constexpr int value = find_type<0, Type, Types...>::value;
};
template<typename ...Bases>
struct Foo : public Bases...
{
using base_types_list = type_list<Bases...>;
};
int main()
{
using T = Foo<BaseA, BaseB, BaseC>;
Foo<BaseA, BaseB, BaseC> q;
int a = get_idx_for_type<BaseA, T::base_types_list>::value;
std::cout << a << std::endl;
return 0;
}
An internal compiler error is always a bug in the compiler, whether or not there
is anything wrong with your code. To work around this one, you can replace:
template<int I, typename T, typename U, typename ...Rest>
struct find_type< I, T, U, Rest... >
{
// problematic line for compiler, problem is somewhere in find_type recursion
static constexpr int value = std::is_same<T, U>::value ? I : find_type<I + 1, T, Rest...>::value;
};
with:
template<int I, typename T, typename U, typename V, typename ...Rest>
struct find_type< I, T, U, V, Rest... >
{
static constexpr int value = std::is_same<T, U>::value ? I : find_type<I + 1, T, V, Rest...>::value;
};
to assist VC++ in disambiguating it from:
template<int I, typename T, typename U>
struct find_type< I, T, U >
{
static constexpr int value = std::is_same<T, U>::value ? I : -1;
};
when ...Rest is empty.
Live demo
I'm getting an internal compiler error "fatal error C1001: An internal error has occurred in the compiler.".
So, I suppose, your code is correct but the compiler is bugged.
I'm looking for some workaround or maybe an error in my code.
I don't have your compiler, so it's a shoot in the dark, but I propose to rewrite your find_type struct using another specialization (a specialization for U and T are the same type; a specialization for U and T are different) and inherit the value from std::integral_constant.
So I propose the following
template <int, typename ...>
struct find_type;
template <int I, typename T>
struct find_type<I, T> : public std::integral_constant<int, -1>
{ };
template <int I, typename T, typename ... Rest>
struct find_type<I, T, T, Rest...> : public std::integral_constant<int, I>
{ };
template <int I, typename T, typename U, typename ... Rest>
struct find_type<I, T, U, Rest...> : public find_type<I+1, T, Rest...>
{ };
Another possible alternative is pass through a template function, instead of a find_type struct.
By example... if you define a static constexpr method find_type_func() as follows (C++17, but I can easily adapt it to C++14 if you want)
template <typename T, typename ... List>
constexpr static int find_type_func ()
{
int ret { -1 };
int i { 0 };
((ret = (ret == -1) && std::is_same<T, List>{} ? i : ret, ++i), ...);
return ret;
}
you can delete the struct find_type and initialize value as follows
static constexpr int value = find_type_func<Type, Types...>();
-- EDIT --
As asked, a C++14 version
template <typename T, typename ... List>
constexpr static int find_type_func ()
{
using unused = int[];
int ret { -1 };
int i { 0 };
(void)unused { 0, (std::is_same<T, List>::value ? ret = i : ++i)... };
return ret;
}
Related
I'm having a hard time getting this simple thing going.
One thing I found that works:
#include <type_traits>
struct A
{
int Method();
};
static_assert( std::is_same_v<
decltype(A{}.Method()), int
>
); // pass. cool.
Ok great. But no; not great. Because I now have a default constructible requirement, AND I need to write a call expression with all arguments. And who knows about them !
Consider the real situation:
struct A
{
int Method(MysteriousArgumentsIDontCareAboutAndCanChangeInTheFuture);
};
static_assert( std::is_same_v<
decltype(A{}.Method()), int
>
); // not so cool anymore (too few arguments to function call, expected 1, have 0)
How about using std::invoke_result ?
static_assert( std::is_same_v<
std::invoke_result_t< A::Method >, int
>
);
nah.
call to non-static member function without an object argument
MSVC says
non-standard syntax; use '&' to create a pointer to member
I can fiddle all I want with this expression, nothing good comes out of it.
e.g.:
using T = std::invoke_result_t< decltype(&A::Method) >;
error: no type named 'type' in 'std::invoke_result
If I remove the decltype it's type-value mismatch (of course) etc...
cppreference.com mentions this usage for the C++14 version:
std::result_of<decltype(&C::Func)(C, char, int&)>::type
Not much better than my first attempt. All the arguments are still there.
In action in our simple case: https://godbolt.org/z/KtQbth
Help ?
You can use the trait suggested by Piotr Skotnicki:
template <typename T>
struct return_type;
template <typename R, typename... Args>
struct return_type<R(Args...)> { using type = R; };
template <typename R, typename... Args>
struct return_type<R(*)(Args...)> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...)> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) &> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) &&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) volatile> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) volatile&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) volatile&&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const volatile> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const volatile&> { using type = R; };
template <typename R, typename C, typename... Args>
struct return_type<R(C::*)(Args...) const volatile&&> { using type = R; };
template <typename T>
using return_type_t = typename return_type<T>::type;
Now you can do:
static_assert(std::is_same_v<return_type_t<decltype(&A::Method)>, int>);
[static_assert( std::is_same_v< decltype(std::declval<A>().Method()), int >);//super cool now][1]
Is there a utility in the standard library to get the index of a given type in std::variant? Or should I make one for myself? That is, I want to get the index of B in std::variant<A, B, C> and have that return 1.
There is std::variant_alternative for the opposite operation. Of course, there could be many same types on std::variant's list, so this operation is not a bijection, but it isn't a problem for me (I can have first occurrence of type on list, or unique types on std::variant list).
Update a few years later: My answer here may be a cool answer, but this is the correct one. That is how I would solve this problem today.
We could take advantage of the fact that index() almost already does the right thing.
We can't arbitrarily create instances of various types - we wouldn't know how to do it, and arbitrary types might not be literal types. But we can create instances of specific types that we know about:
template <typename> struct tag { }; // <== this one IS literal
template <typename T, typename V>
struct get_index;
template <typename T, typename... Ts>
struct get_index<T, std::variant<Ts...>>
: std::integral_constant<size_t, std::variant<tag<Ts>...>(tag<T>()).index()>
{ };
That is, to find the index of B in variant<A, B, C> we construct a variant<tag<A>, tag<B>, tag<C>> with a tag<B> and find its index.
This only works with distinct types.
I found this answer for tuple and slightly modificated it:
template<typename VariantType, typename T, std::size_t index = 0>
constexpr std::size_t variant_index() {
static_assert(std::variant_size_v<VariantType> > index, "Type not found in variant");
if constexpr (index == std::variant_size_v<VariantType>) {
return index;
} else if constexpr (std::is_same_v<std::variant_alternative_t<index, VariantType>, T>) {
return index;
} else {
return variant_index<VariantType, T, index + 1>();
}
}
It works for me, but now I'm curious how to do it in old way without constexpr if, as a structure.
You can also do this with a fold expression:
template <typename T, typename... Ts>
constexpr size_t get_index(std::variant<Ts...> const&) {
size_t r = 0;
auto test = [&](bool b){
if (!b) ++r;
return b;
};
(test(std::is_same_v<T,Ts>) || ...);
return r;
}
The fold expression stops the first time we match a type, at which point we stop incrementing r. This works even with duplicate types. If a type is not found, the size is returned. This could be easily changed to not return in this case if that's preferable, since missing return in a constexpr function is ill-formed.
If you dont want to take an instance of variant, the argument here could instead be a tag<variant<Ts...>>.
With Boost.Mp11 this is a short, one-liner:
template<typename Variant, typename T>
constexpr size_t IndexInVariant = mp_find<Variant, T>::value;
Full example:
#include <variant>
#include <boost/mp11/algorithm.hpp>
using namespace boost::mp11;
template<typename Variant, typename T>
constexpr size_t IndexInVariant = mp_find<Variant, T>::value;
int main()
{
using V = std::variant<int,double, char, double>;
static_assert(IndexInVariant<V, int> == 0);
// for duplicates first idx is returned
static_assert(IndexInVariant<V, double> == 1);
static_assert(IndexInVariant<V, char> == 2);
// not found returns ".end()"/ or size of variant
static_assert(IndexInVariant<V, float> == 4);
// beware that const and volatile and ref are not stripped
static_assert(IndexInVariant<V, int&> == 4);
static_assert(IndexInVariant<V, const int> == 4);
static_assert(IndexInVariant<V, volatile int> == 4);
}
One fun way to do this is to take your variant<Ts...> and turn it into a custom class hierarchy that all implement a particular static member function with a different result that you can query.
In other words, given variant<A, B, C>, create a hierarchy that looks like:
struct base_A {
static integral_constant<int, 0> get(tag<A>);
};
struct base_B {
static integral_constant<int, 1> get(tag<B>);
};
struct base_C {
static integral_constant<int, 2> get(tag<C>);
};
struct getter : base_A, base_B, base_C {
using base_A::get, base_B::get, base_C::get;
};
And then, decltype(getter::get(tag<T>())) is the index (or doesn't compile). Hopefully that makes sense.
In real code, the above becomes:
template <typename T> struct tag { };
template <std::size_t I, typename T>
struct base {
static std::integral_constant<size_t, I> get(tag<T>);
};
template <typename S, typename... Ts>
struct getter_impl;
template <std::size_t... Is, typename... Ts>
struct getter_impl<std::index_sequence<Is...>, Ts...>
: base<Is, Ts>...
{
using base<Is, Ts>::get...;
};
template <typename... Ts>
struct getter : getter_impl<std::index_sequence_for<Ts...>, Ts...>
{ };
And once you establish a getter, actually using it is much more straightforward:
template <typename T, typename V>
struct get_index;
template <typename T, typename... Ts>
struct get_index<T, std::variant<Ts...>>
: decltype(getter<Ts...>::get(tag<T>()))
{ };
That only works in the case where the types are distinct. If you need it to work with independent types, then the best you can do is probably a linear search?
template <typename T, typename>
struct get_index;
template <size_t I, typename... Ts>
struct get_index_impl
{ };
template <size_t I, typename T, typename... Ts>
struct get_index_impl<I, T, T, Ts...>
: std::integral_constant<size_t, I>
{ };
template <size_t I, typename T, typename U, typename... Ts>
struct get_index_impl<I, T, U, Ts...>
: get_index_impl<I+1, T, Ts...>
{ };
template <typename T, typename... Ts>
struct get_index<T, std::variant<Ts...>>
: get_index_impl<0, T, Ts...>
{ };
My two cents solutions:
template <typename T, typename... Ts>
constexpr std::size_t variant_index_impl(std::variant<Ts...>**)
{
std::size_t i = 0; ((!std::is_same_v<T, Ts> && ++i) && ...); return i;
}
template <typename T, typename V>
constexpr std::size_t variant_index_v = variant_index_impl<T>(static_cast<V**>(nullptr));
template <typename T, typename V, std::size_t... Is>
constexpr std::size_t variant_index_impl(std::index_sequence<Is...>)
{
return ((std::is_same_v<T, std::variant_alternative_t<Is, V>> * Is) + ...);
}
template <typename T, typename V>
constexpr std::size_t variant_index_v = variant_index_impl<T, V>(std::make_index_sequence<std::variant_size_v<V>>{});
If you wish a hard error on lookups of not containing type or duplicate type - here are static asserts:
constexpr auto occurrences = (std::is_same_v<T, Ts> + ...);
static_assert(occurrences != 0, "The variant cannot have the type");
static_assert(occurrences <= 1, "The variant has duplicates of the type");
Another take on it:
#include <type_traits>
namespace detail {
struct count_index {
std::size_t value = 0;
bool found = false;
template <typename T, typename U>
constexpr count_index operator+(const std::is_same<T, U> &rhs)
{
if (found)
return *this;
return { value + !rhs, rhs};
}
};
}
template <typename Seq, typename T>
struct index_of;
template <template <typename...> typename Seq, typename... Ts, typename T>
struct index_of<Seq<Ts...>, T>: std::integral_constant<std::size_t, (detail::count_index{} + ... + std::is_same<T, Ts>{}).value> {
static_assert(index_of::value < sizeof...(Ts), "Sequence doesn't contain the type");
};
And then:
#include <variant>
struct A{};
struct B{};
struct C{};
using V = std::variant<A, B, C>;
static_assert(index_of<V, B>::value == 1);
Or:
static_assert(index_of<std::tuple<int, float, bool>, float>::value == 1);
See on godbolt: https://godbolt.org/z/7ob6veWGr
I'm writing a template that defines a type that is given to it in type parameter pack, and whose position is the same as number passed to the template. Here's what I've written:
template<size_t I, typename T, typename... Ts>
struct get_type {
typedef typename std::conditional<I == 0, T, typename get_type<I-1, Ts...>::type>::type type;
};
template<size_t I, typename T>
struct get_type<I, T> {
// This works only if compiler stops unfolding the template when I == 0
static_assert(I == 0, "get_type - index out of bounds");
typedef T type;
};
Problem with this approach, if we write code like this:
static_assert(std::is_same<double, get_type<1,int,double,float>::type>::value, "I wanted double!");
Compiler still "unfolds" the template to the end (even though it should know the type till then, exactly when I is equal to 0), and at the end I overflows and is no longer equal to 0, which means static_assert throws error, that index I is out of bounds. But I still want to somehow throw an error during compile time, if I is TRULLY out of bounds. Is there any way to do that?
The compiler has to unfold the template otherwise it wouldn't know what the type of type is.
std::tuple_element_t already gives a (rather verbose) error if the index is out of bounds.
template<size_t I, typename... Ts>
using get_type_t = std::tuple_element_t<I, std::tuple<Ts...>>;
A more intuitive error message can be made by using this in concert with an explicit bounds check:
template<size_t I, typename... Ts>
struct get_type {
using L=std::tuple<Ts...>;
static_assert(I < 0 || I >= std::tuple_size<L>(), "out of bounds");
using type = std::tuple_element_t<I, L>;
};
template<size_t I, typename... Ts>
using get_type_t = typename get_type<I, Ts...>::type;
Here's an example without the overhead of std::tuple (adapted from boostcon):
struct empty{};
template<class T>
struct tag_t:empty{};
template<class T>
tag_t<T> tag{};
template <typename ignore>
struct lookup;
template <std::size_t... ignore>
struct lookup<std::index_sequence<ignore...>> {
template <typename nth>
static nth
apply(decltype(ignore, empty())..., tag_t<nth>, ...);
};
template<std::size_t I, class... Ts>
using get_type = decltype(
lookup<std::make_index_sequence<I>>::apply(tag<Ts>...)
);
// Test
static_assert(std::is_same<get_type<1, int, float, int>, float>(), "");
static_assert(std::is_same<get_type<0, int, float, int>, int>(), "");
Here's an answer I came up with:
struct error_type {};
template<size_t I, typename T, typename... Ts>
struct get_type {
typedef typename std::conditional<I == 0, T, typename get_type<I-1, Ts...>::type>::type type;
static_assert(!std::is_same<type, error_type>::value, "get_type - index out of bounds");
};
template<size_t I, typename T>
struct get_type<I, T> {
typedef typename std::conditional<I == 0, T, error_type>::type type;
};
But it seems a little verbose (we're creating a dummy structure), so I'm leaving this question in case someone comes up with something smarter then my solution...
If I have a tuple with different element types like
std::tuple<T0, T1, T2, ...>
And how to get the index of a element type?
template<class T, class Tuple>
struct Index
{
enum {value = ?;}
};
Thanks.
template <class T, class Tuple>
struct Index;
template <class T, class... Types>
struct Index<T, std::tuple<T, Types...>> {
static const std::size_t value = 0;
};
template <class T, class U, class... Types>
struct Index<T, std::tuple<U, Types...>> {
static const std::size_t value = 1 + Index<T, std::tuple<Types...>>::value;
};
See it live at Coliru.
This implementation returns the index of the first occurrence of a given type. Asking for the index of a type that is not in the tuple results in a compile error (and a fairly ugly one at that).
template< size_t I, typename T, typename Tuple_t>
constexpr size_t index_in_tuple_fn(){
static_assert(I < std::tuple_size<Tuple_t>::value,"The element is not in the tuple");
typedef typename std::tuple_element<I,Tuple_t>::type el;
if constexpr(std::is_same<T,el>::value ){
return I;
}else{
return index_in_tuple_fn<I+1,T,Tuple_t>();
}
}
template<typename T, typename Tuple_t>
struct index_in_tuple{
static constexpr size_t value = index_in_tuple_fn<0,T,Tuple_t>();
};
The example above avoids generating tons of sub tuples, which makes compilation fail (out of memory) when you call index_in_tuple for large tuples
With constexpr "function" (or lambda), you might do
template <class T, class Tuple>
struct Index;
template <class T, typename... Ts>
struct Index<T, std::tuple<Ts...>>
{
static constexpr std::size_t index = [](){
constexpr std::array<bool, sizeof...(Ts)> a{{ std::is_same<T, Ts>::value... }};
// You might easily handle duplicate index too (take the last, throw, ...)
// Here, we select the first one.
const auto it = std::find(a.begin(), a.end(), true);
// You might choose other options for not present.
// As we are in constant expression, we will have compilation error.
// and not a runtime expection :-)
if (it == a.end()) throw std::runtime_error("Not present");
return std::distance(a.begin(), it);
}();
};
Actually requires C++20 as missing constexpr for std functions,
but can easily be rewritten for previous version. (C++11 would be trickier with the strong restriction for constexpr).
Yet another one using fold expression.
It also sets the value to -1 when not found.
template <class X, class Tuple>
class Idx;
template <class X, class... T>
class Idx<X, std::tuple<T...>> {
template <std::size_t... idx>
static constexpr ssize_t find_idx(std::index_sequence<idx...>) {
return -1 + ((std::is_same<X, T>::value ? idx + 1 : 0) + ...);
}
public:
static constexpr ssize_t value = find_idx(std::index_sequence_for<T...>{});
};
live: https://onlinegdb.com/SJE8kOYdv
EDIT:
As suggested by #Jarod42, one may use std::max:
template <class X, class Tuple>
class Idx;
template <class X, class... T>
class Idx<X, std::tuple<T...>> {
template <std::size_t... idx>
static constexpr ssize_t find_idx(std::index_sequence<idx...>) {
return std::max({static_cast<ssize_t>(std::is_same_v<X, T> ? idx : -1)...});
}
public:
static constexpr ssize_t value = find_idx(std::index_sequence_for<T...>{});
};
template<typename X, class Tuple>
inline constexpr ssize_t Idx_v = Idx<X, Tuple>::value;
In case of duplicate type, this version returns the index of the last one.
live: https://onlinegdb.com/WenEBQs0L
template <typename T, typename U, typename... Us>
constexpr auto getIndex() {
if constexpr (is_same_v<T, U>) {
return 0;
} else {
if constexpr (sizeof...(Us)) {
return 1 + getIndex<T, Us...>();
} else {}
}
}
template <typename T, typename U, typename... Us>
constexpr auto getIndex(const tuple<U, Us...> &) {
return getIndex<T, U, Us...>();
}
usage
tuple the_tuple{'\0', 1, 2L, 3.0, "4", string{"5"}};
cout << getIndex<char>(the_tuple) << endl; // 0
cout << getIndex<double>(the_tuple) << endl; // 3
cout << getIndex<const char *>(the_tuple) << endl; // 4
cout << getIndex<string>(the_tuple) << endl; // 5
/* cout << getIndex<short>(the_tuple) << endl; // compile error */
Try this one, which reports error if the tuple is empty, T doesn't exist or not unique in the tuple:
template <template <typename ...> class TT, std::size_t I, typename ...Ts>
struct defer
{
using type = TT<I, Ts...>;
};
template <std::size_t, typename, typename>
struct tuple_index_helper;
template <std::size_t I, typename T, typename U, typename ...Vs>
struct tuple_index_helper<I, T, std::tuple<U, Vs...>>
{
static_assert(!std::is_same_v<T, U>, "Type not unique.");
static constexpr std::size_t index = tuple_index_helper<I, T, std::tuple<Vs...>>::index;
};
template <std::size_t I, typename T>
struct tuple_index_helper<I, T, std::tuple<>>
{
static constexpr std::size_t index = I;
};
template <std::size_t, typename, typename>
struct tuple_index;
template <std::size_t I, typename T, typename U, typename ...Vs>
struct tuple_index<I, T, std::tuple<U, Vs...>>
{
static constexpr std::size_t index = std::conditional_t<std::is_same_v<T, U>, defer<tuple_index_helper, I, T, std::tuple<Vs...>>, defer<tuple_index, I + 1, T, std::tuple<Vs...>>>::type::index;
};
template <std::size_t I, typename T>
struct tuple_index<I, T, std::tuple<>>
{
static_assert(!(I == 0), "Empty tuple.");
static_assert(!(I != 0), "Type not exist.");
};
template <typename T, typename U>
inline constexpr std::size_t tuple_index_v = tuple_index<0, T, U>::index;
Example:
std::tuple<int, float, const char*> t1{};
std::tuple<int, float, int> t2{};
std::tuple<> t3{};
constexpr auto idx = tuple_index_v<float, decltype(t1)>; // idx = 1
// constexpr auto idx2 = tuple_index_v<long long, decltype(t1)> // Error: Type not exist.
// constexpr auto idx3 = tuple_index_v<int, decltype(t2)> // Error: Type not unique.
// constexpr auto idx4 = tuple_index_v<int, decltype(t3)> // Error: Empty tuple.
This does what Qiang does, but it doesn't have that strange looking empty else branch.
It also makes sure that a tuple with unique types gets passed to it for good measure.
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...>>{};
template <typename T, typename U, typename... Us>
constexpr auto getIndexImpl() {
if constexpr (std::is_same<T, U>::value) {
return 0;
} else {
static_assert(sizeof...(Us) > 0, "This tuple does not have that type");
return 1 + getIndexImpl<T, Us...>();
}
}
template <typename T, typename U, typename... Us>
constexpr auto getIndex(const std::tuple<U, Us...> &) {
static_assert(is_unique<U, Us...>, "getIndex should only be called on tuples with unique types.");
return getIndexImpl<T, U, Us...>();
}
How can I make a class template that returns whether any of its variadic types are equal to the first type. I want to be able to do this:
is_same<T, A, B, C>::value; // true if T is one of A, B or C
And if T is equal to any one of those types, its static value member will be true, otherwise false. How can I do this?
Nice and concise with C++17:
template <class T, class... Ts>
struct is_any : std::disjunction<std::is_same<T, Ts>...> {};
And the dual:
template <class T, class... Ts>
struct are_same : std::conjunction<std::is_same<T, Ts>...> {};
A variation that uses fold expressions:
template <class T, class... Ts>
struct is_any : std::bool_constant<(std::is_same_v<T, Ts> || ...)> {};
template <class T, class... Ts>
struct are_same : std::bool_constant<(std::is_same_v<T, Ts> && ...)> {};
Use template recursion:
template<typename T, typename... Rest>
struct is_any : std::false_type {};
template<typename T, typename First>
struct is_any<T, First> : std::is_same<T, First> {};
template<typename T, typename First, typename... Rest>
struct is_any<T, First, Rest...>
: std::integral_constant<bool, std::is_same<T, First>::value || is_any<T, Rest...>::value>
{};
static_assert(is_any<int, char, double, int>::value, "error 1"); // OK
static_assert(is_any<int, char, double, short>::value, "error 2"); // error
In C++17 you have an even nicer solution, using template variables and fold expressions:
template<class T, class... Rest>
inline constexpr bool are_all_same = (std::is_same_v<T, Rest> && ...);
And the usage is also simpler than all other examples:
are_all_same<T, A, B, C>
No ::value, no parentheses!
Something like this. First, a small metaprogramming library, because it adds like 2 lines to do it generically:
template<template<typename,typename>class checker, typename... Ts>
struct is_any_to_first : std::false_type {};
template<template<typename,typename>class checker, typename T0, typename T1, typename... Ts>
struct is_any_to_first<checker, T0, T1, Ts...> :
std::integral_constant< bool, checker<T0, T1>::value || is_any_to_first<checker, T0, Ts...>::value>
{};
Then a 2 line implementation of is_any_same_to_first:
template<typename... Ts>
using is_any_same_to_first = is_any_to_first< std::is_same, Ts... >;
And for completeness, the original is_all, which may also prove useful:
template<template<typename,typename>class checker, typename... Ts>
struct is_all : std::true_type {};
template<template<typename,typename>class checker, typename T0, typename T1, typename... Ts>
struct is_all<checker, T0, T1, Ts...> :
std::integral_constant< bool, checker<T0, T1>::value && is_all<checker, T0, Ts...>::value>
{};
template<typename... Ts>
using is_all_same = is_all< std::is_same, Ts... >;
Live example of the is_all_same.
Note that calling is_any_same_to_first anything less explicit is asking for trouble. 2/3 people who tried to answer this question, including me, assumed that is_same<A,B,C> is true iff all three are the same type!
Using the relaxed C++14 constexpr functions, these kinds of things are much easier to code, and probably much faster to compile as well, so you could write:
template <class T, class ... Candidates>
constexpr bool is_all_same() {
bool pairs[] = {std::is_same<T,Candidates>::value...};
for(bool p: pairs) if(!p) return false;
return true;
}
template <class T, class ... Candidates>
constexpr bool is_any_same() {
bool pairs[] = {std::is_same<T,Candidates>::value...};
for(bool p: pairs) if(p) return true;
return false;
}
This is enabled by the fact that in C++14 constexpr functions can have for loops.
The most generic version that works :
since C++11
without dependencies (no #include <type_traits> needed)
only one name is_same works for n-types (no is_same_all needed)
template <typename First, typename Second, typename ... Next>
struct is_same {
template <typename A, typename B>
struct is_same_min {
enum { value = false };
};
template <typename A>
struct is_same_min<A,A> {
enum { value = true };
};
template <typename X, typename Y>
constexpr static bool check() {
return is_same_min<X,Y>::value;
};
template <typename X, typename Y, typename Z, typename ... K>
constexpr static bool check() {
return is_same_min<X,Y>::value and check<Y, Z, K...>();
};
enum { value = check<First, Second, Next...>() };
};
Just use is_same<T1,T2,T3...>::value