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

基于std::ranges管道风格的std::variant访问器实现求助

问题:实现带编译时检查的std::variant链式访问器

受std::ranges和std::view的管道操作符(|)启发,希望封装std::get_if和std::visit模式,实现一个**可原地构造、非修改(支持constexpr)**的包装器,用于处理std::variant<...>(包括std::optional<std::variant<...>>),允许通过lambda指定对应类型的处理逻辑。

设计思路采用「可选变体访问器视图」的链式单子方案:

  • 用<<操作符处理nullopt场景(适配C17-C20)
  • 计划用C20模板概念替代C14风格写法

期望用法示例

int main() {
   std::optional<std::variant<int, float, bool>> myVariant = 42;
   /* 注:构建调用链时可任意排序,但不可重复添加同一类型的处理,如多次传入type<int>,第二次应触发静态断言“int类型已被处理” */
   variants(myVariant) << no_option([]() { /* 处理variant为std::nullopt的逻辑,无需可注释*/; })
        | on_type<bool>([](const auto& value) {})
        | on_type<int>([](const auto& value) {}) 
    //  | on_type<string>([](const auto& value) {}) // 应触发静态断言:类型不在variant成员列表中
        | on_type<float>([](const auto& value) {})
    //  | on_type<int>([](const auto& value) {}) // 应触发静态断言:处理链中存在重复类型
        | no_type(); // 若variant存在未处理的类型,链结束检查器会触发静态断言,无需强制处理可注释

   return 0;
}

现有代码实现(存在编译时检查缺陷)

template <typename T>
struct on_type {
    using type_t = T;
    on_type(std::function<void(const T&)> callback) : callback_func(callback) {}

    void if_type(const T& value) const { callback_func(value); }
    std::function<void(const T&)> callback_func;
};

struct no_type {
    // TODO: 添加decltype decay等以在静态断言中打印类型
    template <bool asserted, typename unhandled_in_chain>
    void if_true() const { static_assert(asserted, "type X not handled in chain"); }
};

struct no_option {
    no_option(std::function<void()> callback) : callback_func(std::move(callback)) {}
    void if_true() const { callback_func(); }
    std::function<void()> callback_func;
};

template <typename... Ts>
struct VariantHandler {

    using variant_t = std::variant<Ts...>;
    using optional_variant_t = std::optional < variant_t >;

    VariantHandler( const variant_t& from ) : variant_holder(from) {}
    VariantHandler( const optional_variant_t &from ) {
        if (from.has_value())
            variant_holder = from;
        else
            variant_holder = std::nullopt;
    }

    optional_variant_t variant_holder;

    mutable std::unordered_set<std::size_t> processedTypes{};

    template <typename T>
    const VariantHandler< Ts... > & operator | (const on_type<T>& type_handler) const {
        // FIXME 表达式无法在编译时求值
        //static_assert(processedTypes.contains(typeid(T).hash_code()) == 0, "Duplicate type handler encountered");
        processedTypes.insert(typeid(T).hash_code());

        if (true == variant_holder.has_value()) {
            std::visit([&](const auto& value) {
                if constexpr (std::is_same_v<std::decay_t<decltype(value)>, T>) {
                    type_handler.if_type(value);
                }
            }, variant_holder.value());
        }

        return *this; // 或返回代理对象以支持后续链式调用
    }

    const VariantHandler< Ts... > operator << (const no_option &on_true) const {
        if (false == variant_holder.has_value())
            on_true.if_true();
        return *this;
    }

    // 处理variant中未通过on_type链处理的所有剩余类型
    //template <typename T>
    constexpr void operator | (const no_type& when_no_type) const {
        // TODO: 如何检查链中未注册的类型处理?
        when_no_type.if_true<true, bool>();
    }

    // TODO: 若使用no_type作为链的最后参数,需确定遗漏处理的类型并触发断言
};

// TODO: 添加'requires'约束以校验variant类型,并对on_type<T>中T不属于Ts...的情况触发静态断言
template <typename... Ts>
constexpr auto variants(const std::variant<Ts...>& variant) {
    return VariantHandler<Ts...>{variant};
}
template <typename... Ts>
constexpr auto variants(const std::optional<std::variant<Ts...>>& optional_variant) {
    return VariantHandler<Ts...>{optional_variant};
}

需要解决的核心问题

当前代码无法实现编译时的类型校验,需完成以下三点:

  • 对on_type<T>中的T进行校验:若T不属于目标std::variant的成员类型,触发静态断言
  • 链式调用中禁止重复添加同一类型的处理:若多次调用on_type<T>,第二次触发静态断言
  • 当链末尾使用no_type()时,检查是否处理了std::variant的所有成员类型:存在未处理类型则触发静态断言

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 06:13:20