如何让模板类嵌套类B根据T是否为void决定成员数量
实现模板类A的嵌套类B的条件成员存储
需求明确:
- 当模板类A的参数
T为void时,嵌套类B仅包含size_t sz成员,且sizeof(B)严格等于sizeof(size_t) - 当
T不为void时,B同时包含size_t sz和T类型的成员
已尝试方案的局限
- 位域方案:仅支持整数类型,且无法直接命名
T类型成员(命名位域宽度为0会触发编译错误),访问数据不便
static constexpr bool is_void = std::is_same_v<void, T>; using type = std::conditional_t<is_void, bool, T>; struct B { size_t sz; type : (is_void ? 0 : sizeof(type)); // 命名位域宽度为0会编译失败,无名称则无法正常访问T成员 };
- 条件继承方案:依赖空基类优化(EBO),虽然可行,但希望用更原生简洁的语法实现
struct empty_class {}; struct container { T t; }; static constexpr bool is_void = std::is_same_v<void, T>; using base = std::conditional_t<is_void, empty_class, container>; struct B : base { size_t sz; };
- 特化
A<void>:会导致大量代码冗余,不符合代码复用原则
实现类似std::span内部存储的方案
参考std::span中std::__detail::__extent_storage的实现思路,我们可以利用带[[no_unique_address]]属性的条件成员,结合std::conditional和空类型来实现零开销的条件存储:
#include <type_traits> template<typename T> class A { private: // 空类型,用于T为void时占位 struct empty_storage {}; // 非void时的存储容器 struct value_storage { T value; }; using storage_type = std::conditional_t<std::is_same_v<T, void>, empty_storage, value_storage>; public: struct B { size_t sz; [[no_unique_address]] storage_type storage; // 提供统一的访问接口 template<typename U = T> std::enable_if_t<!std::is_same_v<U, void>, T&> get_value() { return static_cast<value_storage&>(storage).value; } template<typename U = T> std::enable_if_t<!std::is_same_v<U, void>, const T&> get_value() const { return static_cast<const value_storage&>(storage).value; } }; };
方案说明:
- 当
T为void时,storage_type是empty_storage,结合[[no_unique_address]]属性,空类型不会占用额外内存,此时sizeof(B)等于sizeof(size_t),满足要求 - 当
T不为void时,storage_type是value_storage,包含T类型成员,可通过get_value()接口安全访问 - 无需继承,直接利用类成员的条件类型和
[[no_unique_address]]实现零开销优化,语法更原生简洁
验证:
static_assert(sizeof(A<void>::B) == sizeof(size_t)); static_assert(sizeof(A<int>::B) == sizeof(size_t) + sizeof(int));
内容的提问来源于stack exchange,提问作者Alexander S
相关产品推荐
相关产品推荐

