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
相关产品推荐
相关产品推荐

