如何实现含基类派生对象容器的模板类:自动推导键类型
问题描述
需要构建一套模板类模型:基类模板的派生对象存储在派生模板类的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
相关产品推荐
相关产品推荐

