std::visit的使用与误用:类继承场景下的问题及方案探讨
关于std::visit结合继承实现访问者模式的问题
近期我频繁在代码中使用访问者模式,之前习惯经典实现方式,自从C++17引入std::variant后,我更倾向于结合std::visit来实现该模式,但发现std::visit存在局限性。
我知道std::visit接受lambda,或是实现了variant所有类型operator()重载的结构体/类。但我发现一个问题:当父类实现了所有operator()重载时,子类调用std::visit能正常工作;但如果子类添加了与variant类型无关的operator()重载,代码就会报错,提示std::visit要求访问者必须穷举所有类型。
报错代码示例
#include <iostream> #include <variant> #include <string> #include <vector> using TYPE = std::variant<int, double, float, std::string, std::monostate>; class parentVisitor { public: parentVisitor() = default; std::string operator()(const int value) const {return std::to_string(value);} std::string operator()(const double value) const {return std::to_string(value);} std::string operator()(const float value) const {return std::to_string(value);} std::string operator()(std::string value) const {return value;} std::string operator()(std::monostate) const {return "";} }; class childVisitor : public parentVisitor { private: TYPE m_value; public: // 下面这行代码会引发错误! void operator()(std::vector<int> value) const {} explicit childVisitor(TYPE value) : m_value(std::move(value)) {}; void printValue() { const std::string text = std::visit(*this, m_value); std::cout << text << std::endl; } }; int main() { std::string text = "CPP"; childVisitor visitor(text); visitor.printValue(); return 0; }
错误信息
error: static assertion failed due to requirement 'is_invocable_v<childVisitor &, int &>': `std::visit` requires the visitor to be exhaustive. 611 | static_assert(is_invocable_v<_Visitor, _Values...>, "`std::visit` requires the visitor to be exhaustive.");
我尝试在父类中实现visit_parent方法,让子类调用该方法来规避问题,修改后的代码可以正常运行。现在想咨询以下问题:
- 这个规避方案是否合理?
- 还有哪些基于类继承的访问者模式实现方式?
内容的提问来源于stack exchange,提问作者Sukrit Ghorai
相关产品推荐
相关产品推荐

