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

如何实现含基类派生对象容器的模板类:自动推导键类型

问题描述

需要构建一套模板类模型:基类模板的派生对象存储在派生模板类的std::unordered_map中,每个对象拥有唯一键,键支持POD、结构体等多种数据类型。当前核心问题是:无法让派生容器类自动推导传入子类的键类型,作为内部std::unordered_map的键类型,尤其是当子类是基类特化后的非模板类时。注意:容器自身的ID类型与所包含元素的ID类型是不同的。

现有实现代码

// 基类模板
template <typename IDType> class XRObject {
public:
    XRObject() : ID_() {}
    XRObject( const IDType& id) : ID_(id) {}
    XRObject(const XRObject& other) : ID_(other.ID_) {}
    virtual ~XRObject() = default;

    IDType getID() const { return ID_; }
    void setID(const IDType& id) { ID_= id; };

private:
    IDType ID_;
};

// 派生容器类
template <class IDType=long, class T=XRObject> class XRObjectContainer : public XRObject<IDType> {
public:
    using ptr_type = typename std::shared_ptr<T>;
    // 此处无法自动获取T的IDType,原代码用**标记需自动推导的位置
    using container_type = typename std::unordered_map<IDType of class T, ptr_type>;

    using iterator = typename container_type::iterator;
    using const_iterator = typename container_type::const_iterator;

    using sorted_containter_type = typename std::multimap<std::wstring, IDType of class T>;
    using sorted_iterator = typename sorted_containter_type::const_iterator;

    XRObjectContainer() : XRObject<IDType>() {}
    XRObjectContainer(IDType id) {}
    XRObjectContainer(const XRObjectContainer& rhs) : XRObject<IDType>(rhs) {}

protected:
    container_type children_;
    sorted_containter_type sortedbyname_;
};

// 特化后的具体类(原代码存在继承错误)
class XRUnit : public XRObject {
public:
    XRUnit::XRUnit() : XRObjectContainer<long, XRUnit>(), Factor_(0.0, true) {}
    XRUnit::XRUnit(long id, double Factor) : XRObjectContainer<long, XRUnit>(id), Factor_(Factor) {}

private:
    XRValue<double> Factor_;
};

// 最终容器类
class XRUnits : public XRObjectContainer<std::string, XRUnit> {
public:
    XRUnits::XRUnits() : XRObjectContainer<std::string, XRUnit>() {}
    XRUnits::XRUnits(const std::string& ID) : XRObjectContainer<std::string, XRUnit>(ID) {}
};

解决方案

1. 给基类模板添加ID类型别名

在XRObject模板中添加公开的类型别名,让所有派生类(包括特化后的非模板类)都能暴露自身的ID类型:

template <typename IDType> class XRObject {
public:
    // 添加类型别名,用于后续提取ID类型
    using id_type = IDType;

    XRObject() : ID_() {}
    XRObject(const IDType& id) : ID_(id) {}
    XRObject(const XRObject& other) : ID_(other.ID_) {}
    virtual ~XRObject() = default;

    IDType getID() const { return ID_; }
    void setID(const IDType& id) { ID_ = id; };

private:
    IDType ID_;
};

2. 修正子类的继承逻辑

原代码中XRUnit错误地继承了XRObjectContainer,且未指定XRObject的模板参数,修正后:

// 直接继承特化后的XRObject<long>,符合模型设计
class XRUnit : public XRObject<long> {
public:
    XRUnit() : XRObject<long>(), Factor_(0.0, true) {}
    XRUnit(long id, double Factor) : XRObject<long>(id), Factor_(Factor) {}

private:
    XRValue<double> Factor_;
};

3. 重构容器模板,自动提取元素ID类型

修改XRObjectContainer模板,通过T::id_type自动获取元素的ID类型,无需手动指定:

// ContainerID:容器自身的ID类型;T:容器存储的元素类型
template <class ContainerID = long, class T> 
class XRObjectContainer : public XRObject<ContainerID> {
public:
    // 从元素类型T中提取其ID类型
    using element_id_type = typename T::id_type;
    using ptr_type = std::shared_ptr<T>;
    // 使用元素的ID类型作为unordered_map的键
    using container_type = std::unordered_map<element_id_type, ptr_type>;
    using iterator = typename container_type::iterator;
    using const_iterator = typename container_type::const_iterator;

    // 排序容器的关联值也使用元素的ID类型
    using sorted_container_type = std::multimap<std::wstring, element_id_type>;
    using sorted_iterator = typename sorted_container_type::const_iterator;

    XRObjectContainer() : XRObject<ContainerID>() {}
    XRObjectContainer(ContainerID id) : XRObject<ContainerID>(id) {}
    XRObjectContainer(const XRObjectContainer& rhs) : XRObject<ContainerID>(rhs) {}

protected:
    container_type children_;
    sorted_container_type sortedbyname_;
};

4. 使用最终容器类

此时XRUnits只需指定自身ID类型为std::string,元素类型为XRUnit,容器会自动识别XRUnit的ID类型为long,并作为内部std::unordered_map的键:

class XRUnits : public XRObjectContainer<std::string, XRUnit> {
public:
    XRUnits() : XRObjectContainer<std::string, XRUnit>() {}
    XRUnits(const std::string& ID) : XRObjectContainer<std::string, XRUnit>(ID) {}
};

特殊情况处理(可选)

如果元素类型T是被包装的类型(比如std::shared_ptr<T>),可以添加类型萃取器来适配:

// 通用类型萃取器
template <typename T>
struct extract_id_type {
    using type = typename T::id_type;
};

// 针对shared_ptr的偏特化
template <typename T>
struct extract_id_type<std::shared_ptr<T>> {
    using type = typename T::id_type;
};

// 在容器中替换为:
using element_id_type = typename extract_id_type<T>::type;

内容的提问来源于stack exchange,提问作者mgampi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 05:35:24