Search code examples
c++c++20c++-concepts

How could I make a concept<A, B> to check if type "A" is derived from template "B<...something...>"?


Minimal, complete, verifiable example on godbolt

I have a concept Trait_AActuallyBTemplate<A, B> to check if type A is an instance of template B, and it works.

How could I create a new concept to check if A inherits from B<...something...>?

#include <vector>
#include <iostream>
namespace hid{
    template <typename T,template<typename... Ty> typename B>
    struct is_mytype : std::false_type { };

    template <typename... A,template<typename... Ty> typename B>
    struct is_mytype<B<A...> ,B> : std::true_type { };

};

template <typename T,template<typename... Ty> typename B>
concept Trait_AActuallyBTemplate = hid::is_mytype<T,B>::value;

//vvv need modifying here
template <typename T,template<typename... Ty> typename B>
concept Trait_AInheritFromBTemplate = hid::is_mytype<T,B>::value; 
//^^^ need modifying here

int main() {
    static_assert(Trait_AActuallyBTemplate<std::vector<int>,std::vector>,"hehe1");
    static_assert(!Trait_AActuallyBTemplate<int,std::vector>,"hehe2");
    struct MyVector : public std::vector<int> {};
    static_assert(Trait_AInheritFromBTemplate<MyVector,std::vector>,"hehe3"); 
    //^^^ Assert only fails here. (It should work. I am sad.)  
}

Solution

  • You check this by attempting to call a dummy (templated) function accepting a pointer to the base. This will reject inaccessible or ambiguous bases, but this is usually desirable.

    namespace detail
    {
        template <template <typename...> typename T, typename ...P>
        constexpr void foo(const T<P...> *) {}
    }
    
    template <typename T, template <typename...> typename U>
    concept InheritsFromTemplate = requires(T *t){detail::foo<U>(t);};
    
    template <typename ...P> struct A {};
    struct B : A<int, float> {};
    struct C {};
    struct D : virtual A<int, float> {};
    struct E : private A<int, float> {};
    struct F : A<int, float>, A<double> {};
    
    static_assert(InheritsFromTemplate<A<int, float>, A>); // Exact match.
    static_assert(InheritsFromTemplate<B, A>); // Inherits.
    static_assert(!InheritsFromTemplate<C, A>); // Doesn't inherit.
    static_assert(InheritsFromTemplate<D, A>); // Virtual inheritance is ok.
    static_assert(!InheritsFromTemplate<E, A>); // Inaccessible base is rejected.
    static_assert(!InheritsFromTemplate<F, A>); // Ambiguous base is rejected.