基于基类类型有条件地隐藏模板中的方法
问题
我定义了一个继承自std::vector或std::list的模板类Test,需要隐藏所有可修改底层容器大小的方法。我知道可以通过using声明隐藏基类方法,但部分需要隐藏的方法仅存在于std::list中。请问能否无需显式重载这些方法,通过std::enable_if语法有条件地隐藏它们?
当前实现代码
template <class ValueType, class BaseType = std::vector<ValueType>, std::enable_if_t<std::is_same_v<BaseType, std::vector<ValueType>> || std::is_same_v<BaseType, std::list<ValueType>>,int> = 0 > struct Test : public BaseType { Test() = default; private: // 隐藏不允许直接调用的基类成员 using BaseType::push_back; using BaseType::insert; using BaseType::assign; using BaseType::emplace_back; using BaseType::resize; using BaseType::swap; // 这些方法仅在BaseType为std::list时需要隐藏,但std::vector中不存在 //using BaseType::merge; //using BaseType::push_front; //using BaseType::splice; //using BaseType::emplace_front; };
现有替代方案(不够优雅)
template<class T> struct CVector : public std::vector<T> { using std::vector<T>::vector; protected: using std::vector<T>::assign; using std::vector<T>::emplace_back; using std::vector<T>::insert; using std::vector<T>::push_back; using std::vector<T>::resize; using std::vector<T>::swap; }; template <class T> struct CList : public std::list<T> { using std::list<T>::list; protected: using std::list<T>::assign; using std::list<T>::emplace_back; using std::list<T>::insert; using std::list<T>::push_back; using std::list<T>::resize; using std::list<T>::swap; using std::list<T>::emplace_front; using std::list<T>::merge; using std::list<T>::push_front; using std::list<T>::splice; }; template <class ValueType, class BaseType = std::vector<ValueType>, std::enable_if_t<std::is_same_v<BaseType, std::vector<ValueType>> || std::is_same_v<BaseType, std::list<ValueType>>,int> = 0 > struct Test : public std::conditional<std::is_same_v<BaseType, std::vector<ValueType>>, CVector<ValueType>, CList<ValueType>>::type { Test() = default; };
解决方案
可以通过特化辅助类或C++20条件声明实现,无需拆分包装基类,更简洁优雅:
方法一:特化混入类(兼容C++11+)
定义基础混入类处理通用隐藏逻辑,再针对std::list特化混入类补充独有方法的隐藏:
#include <vector> #include <list> #include <type_traits> // 基础混入类:隐藏容器共有的修改方法 template <typename Base> struct HideCommonMethods { private: using Base::push_back; using Base::insert; using Base::assign; using Base::emplace_back; using Base::resize; using Base::swap; }; // 针对std::list的特化混入类:额外隐藏list独有的方法 template <typename T> struct HideCommonMethods<std::list<T>> : HideCommonMethods<std::vector<T>> { private: using std::list<T>::merge; using std::list<T>::push_front; using std::list<T>::splice; using std::list<T>::emplace_front; }; template <class ValueType, class BaseType = std::vector<ValueType>, std::enable_if_t<std::is_same_v<BaseType, std::vector<ValueType>> || std::is_same_v<BaseType, std::list<ValueType>>, int> = 0> struct Test : public BaseType, private HideCommonMethods<BaseType> { Test() = default; // 按需暴露基类的安全方法,比如迭代器、大小查询等 using BaseType::begin; using BaseType::end; using BaseType::size; };
方法二:C++20条件using声明
利用C++20的requires从句直接在Test类内实现条件隐藏:
#include <vector> #include <list> #include <type_traits> template <class ValueType, class BaseType = std::vector<ValueType>, std::enable_if_t<std::is_same_v<BaseType, std::vector<ValueType>> || std::is_same_v<BaseType, std::list<ValueType>>, int> = 0> struct Test : public BaseType { Test() = default; private: // 隐藏共有的修改方法 using BaseType::push_back; using BaseType::insert; using BaseType::assign; using BaseType::emplace_back; using BaseType::resize; using BaseType::swap; // 条件隐藏list独有的方法:仅当BaseType是std::list时生效 template <typename B = BaseType> requires std::is_same_v<B, std::list<ValueType>> using B::merge; template <typename B = BaseType> requires std::is_same_v<B, std::list<ValueType>> using B::push_front; template <typename B = BaseType> requires std::is_same_v<B, std::list<ValueType>> using B::splice; template <typename B = BaseType> requires std::is_same_v<B, std::list<ValueType>> using B::emplace_front; };
方案说明
- 方法一通过混入类特化复用通用逻辑,兼容较早的C++标准,避免代码重复。
- 方法二依赖C++20特性,写法更紧凑,无需额外辅助类,直接在目标类内完成条件控制。
- 两种方案都无需单独定义
CVector/CList包装类,比原替代方案更简洁。
内容的提问来源于stack exchange,提问作者STiFU
相关产品推荐
相关产品推荐

