Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect if a type is one of a list of generic types

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.

like image 406
bradgonesurfing Avatar asked Mar 01 '21 12:03

bradgonesurfing


People also ask

How do you find the type of 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. Get an array that contains the generic type arguments, using the GetGenericArguments method.

How do you find a parameter type?

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.

How do you check if a type is a generic type?

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.

What is isgenerictype in Java?

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.

What is a generic type definition?

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).

How do I get a list of generic type arguments?

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.


Video Answer


2 Answers

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

like image 187
463035818_is_not_a_number Avatar answered Oct 29 '22 04:10

463035818_is_not_a_number


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.

like image 45
Enlico Avatar answered Oct 29 '22 04:10

Enlico