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

如何在std::visit中检查std::variant成员的函数可调用性?

问题描述

我正用可变参数模板实现观察者模式:

  • Subject类接收订阅者作为参数,将其存储在std::vector<std::variant<...>>中,notify函数通过std::visit调用订阅者的onMessage函数完成通知。
  • 订阅者类以期望接收的消息类型为模板参数,比如SubscriberOne接收Foo、Bar消息,SubscriberTwo仅接收Foo消息。

当前问题:调用subjectOne.notify(bar)时触发报错,原因是SubscriberTwo没有对应的onMessage(Bar&)函数。想知道能否在std::visit里检查订阅者是否可调用对应onMessage函数,比如用if constexpr结合variant中的类型做判断?

注:已基于CRTP更新了SubscriberBase版本。

解决方案

完全可以通过编译期检查实现这种“选择性通知”,核心是用if constexpr结合SFINAE或C++20概念,判断当前variant持有的订阅者是否支持处理目标消息:

1. 定义可调用性检查工具

C++20及以上(用concept)

直接写一个concept来判断订阅者是否拥有对应消息的onMessage函数:

template<typename Subscriber, typename Msg>
concept HasOnMessage = requires(Subscriber& sub, Msg& msg) {
    { sub.onMessage(msg) } -> std::same_as<void>;
};

C++17及更早(用SFINAE)

用模板特化实现编译期判断:

template<typename Subscriber, typename Msg, typename = void>
struct has_on_message : std::false_type {};

template<typename Subscriber, typename Msg>
struct has_on_message<Subscriber, Msg, std::void_t<decltype(std::declval<Subscriber&>().onMessage(std::declval<Msg&>()))>> : std::true_type {};

template<typename Subscriber, typename Msg>
constexpr bool has_on_message_v = has_on_message<Subscriber, Msg>::value;

2. 在std::visit中加入条件判断

修改notify函数的访问器逻辑,通过if constexpr做编译期分支,只调用能处理当前消息的订阅者:

template<typename Msg>
void notify(Msg& msg) {
    for (auto& subscriber_variant : subscribers_) {
        std::visit([&msg](auto& subscriber) {
            // C++20用concept判断
            if constexpr (HasOnMessage<decltype(subscriber), Msg>) {
                subscriber.onMessage(msg);
            }
            // C++17用SFINAE判断
            // if constexpr (has_on_message_v<decltype(subscriber), Msg>) {
            //     subscriber.onMessage(msg);
            // }
            // 不满足条件时直接跳过,无编译错误
        }, subscriber_variant);
    }
}

这样通知Bar类型消息时,SubscriberTwo因不满足可调用约束会被跳过,不会触发编译报错。

3. 结合CRTP基类优化

如果你的SubscriberBase是CRTP实现的,可以把消息类型支持逻辑整合到基类中,确保订阅者只暴露自己支持的onMessage重载,进一步强化编译期检查的可靠性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 09:47:03