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

C++:为模板函数编写适配std::visit的Visitor的简便方法

问题:简化std::visit的Visitor生成

我正在使用一个重度模板化的库,其中包含一个多模板参数的函数。我希望创建一个动态包装类,以类成员作为该模板函数的参数。我了解到std::visit需要Visitor对象,但即使仅考虑少量模板类,手动编写Visitor辅助类也十分繁琐。是否有更简便的生成Visitor的方法?

手动实现Visitor辅助类的示例

#include <iostream>
#include <variant>

namespace NotMyLibrary
{
class A
{
    public:
    void execute()
    {
        std::cout << "From A!" << std::endl;
    }
};

class B
{
    public:
    void execute()
    {
        std::cout << "From B!" << std::endl;
    }
};

class C
{
    public:
    void apply()
    {
        std::cout << "From C!" << std::endl;
    }
};

class D
{
    public:
    void apply()
    {
        std::cout << "From D!" << std::endl;
    }
};

template<typename AorB, typename CorD>
void library_function_with_static_dependencies(AorB f, CorD g)
{
    size_t num_iterations = 1; //but really 1'000'000+
    for(size_t i=0; i < num_iterations; ++i)
    {
        f.execute();
        g.apply();
        std::cout << std::endl;
    }
}
} //end namespace NotMyLibrary


class VisitHelper
{
    public:
    void operator()(NotMyLibrary::A f, NotMyLibrary::C g) {NotMyLibrary::library_function_with_static_dependencies(f,g);}
    void operator()(NotMyLibrary::A f, NotMyLibrary::D g) {NotMyLibrary::library_function_with_static_dependencies(f,g);}   
    void operator()(NotMyLibrary::B f, NotMyLibrary::C g) {NotMyLibrary::library_function_with_static_dependencies(f,g);}   
    void operator()(NotMyLibrary::B f, NotMyLibrary::D g) {NotMyLibrary::library_function_with_static_dependencies(f,g);}   

};


class DynamicFunctionExecutor
{
    public:
    std::variant<NotMyLibrary::A, NotMyLibrary::B> f;
    std::variant<NotMyLibrary::C, NotMyLibrary::D> g;
    
    void dispatch()
    {
        VisitHelper vh{};
        std::visit(vh, f, g);
    }
};



int main()
{
    using namespace NotMyLibrary;
    DynamicFunctionExecutor e;
    e.f = A();
    e.g = C();
    e.dispatch();
    
    e.f = B();
    e.g = D();
    e.dispatch();
    
}

简化方案

1. 使用泛型Lambda(C++17及以上)

直接在std::visit中传入泛型Lambda,无需手动编写Visitor类。Lambda会自动推导所有std::variant的可能类型组合,调用目标模板函数:

修改DynamicFunctionExecutor的dispatch函数:

void dispatch()
{
    std::visit(
        [](auto&& f_val, auto&& g_val) {
            NotMyLibrary::library_function_with_static_dependencies(
                std::forward<decltype(f_val)>(f_val),
                std::forward<decltype(g_val)>(g_val)
            );
        },
        f, g
    );
}

这样就完全替代了手动编写VisitHelper的工作,代码更简洁且易于维护。

2. 通用模板Visitor(复用场景)

如果需要在多个地方复用这个Visitor逻辑,可以定义一个通用的模板类,接受目标函数作为参数:

template<typename Func>
struct GenericVisitor {
    Func func;

    template<typename... Args>
    auto operator()(Args&&... args) const -> decltype(auto) {
        return func(std::forward<Args>(args)...);
    }
};

使用时直接传入库函数即可:

void dispatch()
{
    std::visit(
        GenericVisitor{NotMyLibrary::library_function_with_static_dependencies},
        f, g
    );
}

这种方式适合需要多次调用同一场景的std::visit,避免重复编写Lambda。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 21:05:54