If I have
template <typename T> struct A;
template <typename T> struct B;
template <typename T> struct C;
template <typename T> struct D;
what is the most compact way of testing if some candidate type X
is one of them? I'm looking for something like
boost::enable_if< is_instantiation_of_any<X,A,B,C,D> >
but A,B,C and D are templates so I'm not sure how to construct the above.
Use the IsGenericType property to determine whether the type is generic, and use the IsGenericTypeDefinition property to determine whether the type is a generic type definition. Get an array that contains the generic type arguments, using the GetGenericArguments method.
You can access the type of a specific parameter by using square brackets, in the same way you would access an array element at index. Here is an example of how you would use the Parameters utility type for 2 functions that take the same object as a parameter.
To examine a generic type and its type parameters Get an instance of Type that represents the generic type. Use the IsGenericType property to determine whether the type is generic, and use the IsGenericTypeDefinition property to determine whether the type is a generic type definition.
A Type object representing a generic type from which the current type can be constructed. The current type is not a generic type. That is, IsGenericType returns false. The invoked method is not supported in the base class. Derived classes must provide an implementation.
A generic type definition is a template from which other types can be constructed. For example, from the generic type definition G<T> (expressed in C# syntax; G(Of T) in Visual Basic or generic <typename T> ref class G in C++) you can construct and instantiate the type G<int> (G(Of Integer) in Visual Basic).
Get an array that contains the generic type arguments, using the GetGenericArguments method. For each type argument, determine whether it is a type parameter (for example, in a generic type definition) or a type that has been specified for a type parameter (for example, in a constructed type), using the IsGenericParameter property.
Not sure if there exists a std::is_instantiation_of
, though if all templates have same number of parameters, it is straightforward to implement it (if they don't it is more complicated). To check if a type is an instantiation of any of given templates you just need to fold it (requires C++17):
#include<iostream>
#include<type_traits>
template <typename T> struct A;
template <typename T> struct B;
template <typename T> struct C;
template <typename T> struct D;
template <typename T,template<typename> typename X>
struct is_instantiation_of : std::false_type {};
template <typename A,template<typename> typename X>
struct is_instantiation_of<X<A>,X> : std::true_type {};
template <typename T,template<typename> typename...X>
struct is_instantiation_of_any {
static const bool value = ( ... || is_instantiation_of<T,X>::value);
};
int main(){
std::cout << is_instantiation_of< A<int>, A>::value;
std::cout << is_instantiation_of< A<double>, B>::value;
std::cout << is_instantiation_of_any< A<int>,A,B>::value;
}
Output:
101
To get a C++11 compliant solution, we can use this neat trick from one of Jarod42s answers:
template <bool ... Bs> using meta_bool_and = std::is_same<std::integer_sequence<bool, true, Bs...>, std::integer_sequence<bool, Bs..., true>>;
Its rather clever, true,a,b,c
and a,b,c,true
are only the same when a
, b
and c
are all true
. std::integer_sequence
is C++14, but all we need here is a type that has the bools as part of its definition:
namespace my {
template <typename T,T ...t>
struct integer_sequence {};
}
Using that we can rewrite the above to:
template <bool ... Bs>
using my_all = std::is_same<my::integer_sequence<bool, true, Bs...>,
my::integer_sequence<bool, Bs..., true>>;
And as "ANY(a,b,c,d,...)"
is just "! ALL( !a, !b, !c, !d,...)"
we can use:
template <bool ... Bs>
struct my_any { static constexpr bool value = ! my_all< ! Bs...>::value; };
to write is_instantiation_of_any
in a C++11 friendly way:
template <typename T,template<typename> typename...X>
struct is_instantiation_of_any {
static const bool value = my_any< is_instantiation_of<T,X>::value ...>::value;
};
Complete C++11 example
With C++17 (or C++14 if you edit as per the comments), you can use boost::hana::any_of
as a helper:
#include <iostream>
#include <boost/hana/any_of.hpp>
#include <boost/hana/tuple.hpp>
#include <type_traits>
namespace hana = boost::hana;
template <typename T> struct A {};
template <typename T> struct B {};
template <typename T> struct C {};
template <typename T> struct D {};
template <typename T> struct N {};
template<typename T>
bool fun(T) { // overload for non-templated arguments (templated arguments
return false; // are a better match for the overload below)
}
template<typename T, template<typename> typename X>
bool fun(X<T>) { // overload for templated arguments
auto constexpr pred = [](auto x){ // remove constexpr for < c++17
return std::is_same_v<decltype(x), X<T>>;
// return std::is_same<decltype(x), X<T>>::value; // for < c++17
};
return hana::any_of(hana::tuple<A<T>, B<T>, C<T>, D<T>>{}, pred);
};
int main() {
A<int> a{};
N<int> b{};
int x = 3; fun(x);
std::cout << fun(a) << fun(b) << fun(x) << std::endl; // prints 100
}
Probably you want to use std::decay_t
before passing things to std::is_same_v
.
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