You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++20中如何判断类型是否继承自vector/list/deque?

如何让C++20类型特性支持判断容器的派生类?

问题背景

我正在使用C++20,已通过以下代码实现判断某类型是否为std::vector、std::list或std::deque:

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

现在希望is_listish能支持判断继承自这些容器的派生类,例如:

struct MyVec : public std::vector<int> { };
static_assert(is_listish<MyVec>); // 期望结果为true

尝试了以下代码但编译器报错无法推导B:

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

错误原因分析

上述特化代码的问题在于:模板参数B没有出现在特化的类型参数列表(即<D>)中,编译器无法从D推导出B的具体类型,因此无法匹配这个特化模板。这种写法不符合C++模板特化的推导规则。

正确实现方案

借助C++20的requires表达式,我们可以更简洁、直观地实现需求,同时支持原生容器和其派生类:

方案1:直接用requires表达式检查转换

#include <vector>
#include <list>
#include <deque>
#include <type_traits>

// 判断类型本身是否是目标容器之一
template <typename T>
concept IsListishContainer = 
    std::same_as<std::remove_cvref_t<T>, std::vector<typename T::value_type, typename T::allocator_type>> ||
    std::same_as<std::remove_cvref_t<T>, std::list<typename T::value_type, typename T::allocator_type>> ||
    std::same_as<std::remove_cvref_t<T>, std::deque<typename T::value_type, typename T::allocator_type>>;

template <typename T>
constexpr bool is_listish = 
    IsListishContainer<T> || 
    // 检查是否能隐式转换为std::vector的const引用(公有继承允许该转换)
    requires { 
        []<typename U, typename A>(const std::vector<U, A>&) {}(std::declval<const T&>()); 
    } ||
    // 检查是否能隐式转换为std::list的const引用
    requires { 
        []<typename U, typename A>(const std::list<U, A>&) {}(std::declval<const T&>()); 
    } ||
    // 检查是否能隐式转换为std::deque的const引用
    requires { 
        []<typename U, typename A>(const std::deque<U, A>&) {}(std::declval<const T&>()); 
    };

// 测试用例
struct MyVec : public std::vector<int> { };
struct MyList : public std::list<double> { };
struct MyDeque : public std::deque<char> { };

static_assert(!is_listish<int>);
static_assert(is_listish<std::vector<int>>);
static_assert(is_listish<std::list<double>>);
static_assert(is_listish<std::deque<char>>);
static_assert(is_listish<MyVec>);
static_assert(is_listish<MyList>);
static_assert(is_listish<MyDeque>);
static_assert(is_listish<const MyVec>); // 支持const限定的类型

方案2:复用模板容器检查逻辑

可以将容器的检查逻辑封装为通用concept,让代码更简洁:

#include <vector>
#include <list>
#include <deque>
#include <type_traits>

template <typename T>
concept IsListishContainer = 
    std::same_as<std::remove_cvref_t<T>, std::vector<typename T::value_type, typename T::allocator_type>> ||
    std::same_as<std::remove_cvref_t<T>, std::list<typename T::value_type, typename T::allocator_type>> ||
    std::same_as<std::remove_cvref_t<T>, std::deque<typename T::value_type, typename T::allocator_type>>;

// 通用concept:判断T是否派生自指定的模板容器
template <template <typename...> typename Container, typename T>
concept DerivedFromContainer = requires(const T& t) {
    static_cast<const Container<typename T::value_type, typename T::allocator_type>&>(t);
};

template <typename T>
constexpr bool is_listish = 
    IsListishContainer<T> ||
    DerivedFromContainer<std::vector, T> ||
    DerivedFromContainer<std::list, T> ||
    DerivedFromContainer<std::deque, T>;

// 测试用例同上

实现说明

  • 利用公有继承的隐式转换特性:派生类对象可以隐式转换为基类的const引用,通过requires表达式尝试这种转换,就能判断类型是否继承自目标容器;
  • 使用std::remove_cvref_t处理带const、volatile或引用限定的类型,确保类型匹配的准确性;
  • 模板lambda的作用是让编译器自动推导容器的模板参数(元素类型U和分配器A),无需手动指定。

内容的提问来源于stack exchange,提问作者Suraaj K S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 14:39:55