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

如何从std::vector<std::shared_ptr<void>>获取Lambda?定义多返回值Lambda向量

问题:如何定义可存储不同返回值Lambda的std::vector?

问题代码(无法正常运行)

以下代码尝试将不同返回值类型的std::function存储到std::vector<std::shared_ptr<void>>中,但最后一行的调用会编译失败——因为std::shared_ptr<void>无法直接解引用并调用其中的函数:

#include <iostream>
#include <memory>
#include <functional>
#include <vector>

int main()
{
    printf("Hello World\n");
    
    std::function<int()>      dummy1 = []() { return -3; };
    std::function<unsigned()> dummy2 = []() { return 33333; };

    auto test1 = std::make_shared<std::function<int()>>(dummy1);
    auto test2 = std::make_shared<std::function<unsigned()>>(dummy2);

    std::cout << "Final 1: " << (*test1)() << "\n";
    std::cout << "Final 2: " << (*test2)() << "\n";

    std::vector<std::shared_ptr<void>> ptr;

    ptr.push_back(test1);
    ptr.push_back(test2);

    // 编译失败:无法对void类型解引用并调用函数
    // std::cout << "Final 3: " << (*ptr[0])() << "\n";

    return 0;
}

需求背景

计划实现一个用于监控的中央数据结构,用来查询不同模块中返回类型各异的各类获取器(getter)。需要定期调用所有获取器来查询数据,且获取器支持编译时配置。为保持通用实现并仅依赖config.h文件,需尽可能通用地构建该向量(不过我认为避免使用std::any不太妥当)。

解决方案

针对监控场景的需求,有两种实用的实现方式:

方案1:抽象基类+模板派生类(动态多态)

通过定义统一的抽象接口,将不同返回值的获取器包装成派生类,向量存储基类的智能指针,调用时通过多态接口执行。

#include <iostream>
#include <memory>
#include <functional>
#include <vector>

// 统一的监控获取器接口
class MonitorGetter {
public:
    virtual ~MonitorGetter() = default;
    // 可根据需求扩展,比如传入监控数据收集器的引用
    virtual void execute() const = 0;
};

// 模板包装类,适配不同返回值的获取器
template<typename ReturnType>
class GetterWrapper : public MonitorGetter {
private:
    std::function<ReturnType()> m_getter;
public:
    GetterWrapper(std::function<ReturnType()> getter) 
        : m_getter(std::move(getter)) {}
    
    void execute() const override {
        // 这里统一处理监控数据的输出/收集逻辑
        std::cout << "监控数据: " << m_getter() << "\n";
    }
};

int main() {
    std::function<int()> dummy1 = []() { return -3; };
    std::function<unsigned()> dummy2 = []() { return 33333; };

    // 存储统一接口的智能指针
    std::vector<std::shared_ptr<MonitorGetter>> getters;
    getters.emplace_back(std::make_shared<GetterWrapper<int>>(dummy1));
    getters.emplace_back(std::make_shared<GetterWrapper<unsigned>>(dummy2));

    // 定期调用所有获取器
    for (const auto& getter : getters) {
        getter->execute();
    }

    return 0;
}

优点:无需提前枚举所有返回类型,新增类型只需添加对应包装类,扩展性强;缺点:存在轻微的动态多态运行时开销。

方案2:std::variant(静态分发)

如果所有获取器的返回类型在编译时就能确定,可使用std::variant存储不同类型的std::function,通过std::visit执行调用。

#include <iostream>
#include <variant>
#include <functional>
#include <vector>

// 枚举所有可能的获取器类型(编译时确定)
using GetterVariant = std::variant<std::function<int()>, std::function<unsigned()>>;

// 统一执行逻辑
void execute_getter(const GetterVariant& var) {
    std::visit([](auto&& getter) {
        std::cout << "监控数据: " << getter() << "\n";
    }, var);
}

int main() {
    std::vector<GetterVariant> getters;
    getters.emplace_back([]() { return -3; });
    getters.emplace_back([]() { return 33333; });

    // 定期调用所有获取器
    for (const auto& getter : getters) {
        execute_getter(getter);
    }

    return 0;
}

优点:无动态多态开销,实现更简洁;缺点:需要提前枚举所有可能的返回类型,适合编译时配置的场景。

关于std::any的说明

std::any也可用来存储不同类型的获取器,但调用时必须明确转换回原类型才能安全调用,需要额外的类型标记逻辑,在监控这种需要统一执行的场景下,不如上述两种方案直观易用,因此确实不推荐优先使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 16:15:11