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

如何实现两个泛型回调的参数在指定函数中汇合?

可行的实现方案

当然有可行的实现方式!核心思路是类型擦除:当第一个回调被调用时,捕获其值并生成一个等待第二个回调的泛型处理函数,等第二个回调触发时,再把两个值一起传给meet_point。下面分两种场景给出实现:

基础版本(假设foo先于bar调用)

如果你的业务场景中可以保证foo一定先被调用,那么实现非常简洁,利用C++20的泛型lambda和std::function<void(auto)>即可:

#include <functional>
#include <utility>
#include <iostream>

template <class FooType, class BarType> 
void meet_point(FooType foo_value, BarType bar_value) {
    // 这里写你的汇合逻辑,示例打印两个值
    std::cout << "汇合成功:Foo = " << foo_value << ", Bar = " << bar_value << std::endl;
}

struct test {
    // 存储等待bar调用的回调:接收任意类型的bar值
    std::function<void(auto)> pending_bar_handler;

    template <class FooType> 
    void foo(FooType value) {
        // 捕获foo的值,生成泛型lambda等待bar的调用
        pending_bar_handler = [value = std::move(value)](auto bar_value) {
            meet_point(std::move(value), std::move(bar_value));
        };
    }

    template <class BarType> 
    void bar(BarType value) {
        if (pending_bar_handler) {
            pending_bar_handler(std::move(value));
            // 调用后重置,避免重复触发
            pending_bar_handler = nullptr;
        }
    }
};

template <class F> 
void sync_request(F&& f) { 
    f("foobar"); 
}

int main() {
    test t;
    sync_request([&t](auto value) { t.foo(value); });
    t.bar(42); // 触发meet_point("foobar", 42)
}

完善版本(支持任意调用顺序)

如果foo和bar的调用顺序不确定,我们可以用std::variant管理状态,不管哪个回调先触发,都能保存对应的等待逻辑:

#include <functional>
#include <utility>
#include <variant>
#include <iostream>

template <class FooType, class BarType> 
void meet_point(FooType foo_value, BarType bar_value) {
    std::cout << "汇合成功:Foo = " << foo_value << ", Bar = " << bar_value << std::endl;
}

struct test {
    // 状态:无等待 / 已接收foo等待bar / 已接收bar等待foo
    std::variant<std::monostate, std::function<void(auto)>, std::function<void(auto)>> state;

    template <class FooType> 
    void foo(FooType value) {
        std::visit([value = std::move(value)](auto& current_state) {
            using StateType = std::decay_t<decltype(current_state)>;
            if constexpr (std::is_same_v<StateType, std::monostate>) {
                // 未收到任何值,保存等待bar的回调
                current_state = [value = std::move(value)](auto bar_val) {
                    meet_point(std::move(value), std::move(bar_val));
                };
            } else if constexpr (std::is_same_v<StateType, std::function<void(auto)>>) {
                // 已收到bar的等待回调,直接调用(传入foo的值)
                current_state(std::move(value));
                // 重置状态
                current_state = std::monostate{};
            }
        }, state);
    }

    template <class BarType> 
    void bar(BarType value) {
        std::visit([value = std::move(value)](auto& current_state) {
            using StateType = std::decay_t<decltype(current_state)>;
            if constexpr (std::is_same_v<StateType, std::monostate>) {
                // 未收到任何值,保存等待foo的回调
                current_state = [value = std::move(value)](auto foo_val) {
                    meet_point(std::move(foo_val), std::move(value));
                };
            } else if constexpr (std::is_same_v<StateType, std::function<void(auto)>>) {
                // 已收到foo的等待回调,直接调用(传入bar的值)
                current_state(std::move(value));
                // 重置状态
                current_state = std::monostate{};
            }
        }, state);
    }
};

template <class F> 
void sync_request(F&& f) { 
    f("foobar"); 
}

int main() {
    test t;
    // 先调用bar,再调用foo,同样能触发汇合
    t.bar(42);
    sync_request([&t](auto value) { t.foo(value); });
}

关键原理说明

  1. 泛型lambda:C++14及以后支持泛型lambda(参数用auto),它可以适配任意类型的参数,完美匹配我们不确定的回调值类型。
  2. 类型擦除:C++20中std::function支持存储带auto参数的泛型lambda,实现了对具体类型的擦除——我们不需要提前知道foo和bar的参数类型,只需要在调用时动态绑定。
  3. 状态管理:用std::variant可以清晰管理"等待foo"、"等待bar"、"无等待"三种状态,确保不管哪个回调先触发,都能正确汇合。

如果你使用C17或更早版本,std::function不支持泛型lambda的auto参数,这时候需要手动实现更复杂的类型擦除(比如自定义基类+模板子类),或者依赖第三方库(如Boost.Function)。不过C20的方案已经足够简洁且覆盖大多数场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 06:48:16