c++templatesc++20type-traitsc++-templates

How do I check whether a type is derived from vector / list / deque?


I'm using C++20. I was able to check if a type is some vector / deque / list as follows:

template <typename N> struct is_listish_trait {
  static constexpr bool value = 0;
};

/* These are listish specializations */
template <typename N, typename A> struct is_listish_trait<std::vector<N, A>> {
  static constexpr bool value = 1;
};

template <typename N, typename A> struct is_listish_trait<std::list<N, A>> {
  static constexpr bool value = 1;
};

template <typename N, typename A> struct is_listish_trait<std::deque<N, A>> {
  static constexpr bool value = 1;
};

template <typename T>
static constexpr bool is_listish = is_listish_trait<T>::value;

static_assert(!is_listish<int>);
static_assert(is_listish<std::vector<int>>);

(I am wondering if there is a better way to do this in C++20, now that we have requires expressions, etc.)

However, now what I want is for is_listish to accept classes that derive from vectors / lists / deques. For instance:

struct MyVec : public std::vector<int> { };
static_assert(is_listish<MyVec>); //This should be true

I'm not sure if this is possible. This is what I tried:

template <typename B, typename D>
  requires std::is_base_of_v<B, D>
struct is_listish_trait<D> {
  static constexpr bool value = 1;
};

However, the compiler complains that it cannot deduce B (which is understandable).

How can one do this?


Solution

  • With requires, you might do:

    template <typename T>
    concept is_listish =
           requires(T t) { []<typename U, typename A>(std::vector<U, A>&){}(t); }
        or requires(T t) { []<typename U, typename A>(std::list<U, A>&){}(t); }
        or requires(T t) { []<typename U, typename A>(std::deque<U, A>&){}(t); }
        ;
    

    Demo