使std::variant工具兼容继承自std::variant的自定义类型
解决C++23继承std::variant后标准工具兼容问题
在C++23中,我们可以继承std::variant来扩展功能,但标准库提供的std::variant_size、std::variant_alternative、std::is_alternative等工具默认仅支持原生std::variant类型,无法直接作用于继承后的自定义类型。要让static_assert(std::variant_size_v<State> == 2);生效,只需为自定义类型特化这些标准模板即可。
基础特化方案
针对你的State类型,直接特化相关模板:
1. 特化std::variant_size
#include <variant> struct State : std::variant<int, float> { using variant::variant; }; // 特化std::variant_size template<> struct std::variant_size<State> : std::variant_size<std::variant<int, float>> {}; // 特化变量模板variant_size_v template<> inline constexpr std::size_t std::variant_size_v<State> = std::variant_size_v<std::variant<int, float>>;
2. 特化std::variant_alternative
// 特化std::variant_alternative,支持索引访问类型 template<std::size_t I> struct std::variant_alternative<I, State> : std::variant_alternative<I, std::variant<int, float>> {}; // 特化变量模板variant_alternative_t template<std::size_t I> using std::variant_alternative_t<I, State> = typename variant_alternative<I, State>::type;
3. 特化std::is_alternative
// 特化std::is_alternative,检测类型是否为变体的备选类型 template<typename T> struct std::is_alternative<T, State> : std::is_alternative<T, std::variant<int, float>> {}; // 特化变量模板is_alternative_v template<typename T> inline constexpr bool std::is_alternative_v<T, State> = std::is_alternative_v<T, std::variant<int, float>>;
验证代码
添加以下静态断言验证效果:
static_assert(std::variant_size_v<State> == 2); // 正常通过 static_assert(std::is_same_v<std::variant_alternative_t<0, State>, int>); static_assert(std::is_same_v<std::variant_alternative_t<1, State>, float>); static_assert(std::is_alternative_v<int, State>); static_assert(!std::is_alternative_v<double, State>);
通用特化方案(多继承类型场景)
如果有多个继承自std::variant的自定义类型,可编写通用辅助模板避免重复特化:
#include <variant> #include <type_traits> // 辅助模板:检测类型是否继承自std::variant template<typename T> struct is_variant_derived : std::false_type {}; // 匹配原生std::variant template<typename... Ts> struct is_variant_derived<std::variant<Ts...>> : std::true_type {}; // 匹配继承std::variant且暴露了variant别名的类型 template<typename Derived> struct is_variant_derived<Derived> : is_variant_derived<typename Derived::variant> {}; // 通用特化std::variant_size template<typename T> requires is_variant_derived<T>::value struct std::variant_size<T> : std::variant_size<typename T::variant> {}; template<typename T> requires is_variant_derived<T>::value inline constexpr std::size_t std::variant_size_v<T> = std::variant_size_v<typename T::variant>; // 通用特化std::variant_alternative template<std::size_t I, typename T> requires is_variant_derived<T>::value struct std::variant_alternative<I, T> : std::variant_alternative<I, typename T::variant> {}; template<std::size_t I, typename T> requires is_variant_derived<T>::value using std::variant_alternative_t<I, T> = typename variant_alternative<I, T>::type; // 通用特化std::is_alternative template<typename U, typename T> requires is_variant_derived<T>::value struct std::is_alternative<U, T> : std::is_alternative<U, typename T::variant> {}; template<typename U, typename T> requires is_variant_derived<T>::value inline constexpr bool std::is_alternative_v<U, T> = std::is_alternative_v<U, typename T::variant>;
使用时,只需在自定义类型中添加using variant = std::variant<...>;:
struct State : std::variant<int, float> { using variant = std::variant<int, float>; // 暴露基类型别名 using variant::variant; }; struct AnotherState : std::variant<std::string, bool> { using variant = std::variant<std::string, bool>; using variant::variant; }; // 验证 static_assert(std::variant_size_v<State> == 2); static_assert(std::variant_size_v<AnotherState> == 2);
内容的提问来源于stack exchange,提问作者Basti
相关产品推荐
相关产品推荐

