Vu *_*Lam 3 c++ std variant c++17
我正在尝试使用std::visit来检查std::variant.
首先,我声明变体和变体的基(可调用)访问者类:
#include <iostream>
#include <string>
#include <variant>
using Amalgamation = std::variant<int, bool, std::string>;
class BaseVisitor {
public:
virtual void operator()(int) {}
virtual void operator()(bool) {}
virtual void operator()(const std::string&) {}
};
Run Code Online (Sandbox Code Playgroud)
其次,我定义了另一个从上面的基类派生的访问者类:
class CheckBooleanVisitor
: public BaseVisitor {
public:
CheckBooleanVisitor()
: m_isBoolean(false) {
}
virtual void operator()(bool) override { // WHERE THE OVERRIDING TAKES PLACE
m_isBoolean = true;
}
bool isBoolean() const {
return m_isBoolean;
}
};
Run Code Online (Sandbox Code Playgroud)
我使用这个“派生”访问者类来访问如下变体:
int main() {
Amalgamation a(0);
Amalgamation b(false);
CheckBooleanVisitor c;
std::visit(c, a); // LINE #1
std::cout << "a is " << (c.isBoolean() ? "" : "not ") << "a boolean." << std::endl;
std::visit(c, b); // LINE #2
std::cout << "b is " << (c.isBoolean() ? "" : "not ") << "a boolean." << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译器(VS 2022)在LINE #1和中抱怨LINE #2如下:
no instance of function template "std::visit" matches the argument list
但是,如果我尝试:
std::visit((BaseVisitor&)c, a); // LINE #1
std::visit((BaseVisitor&)c, b); // LINE #2
Run Code Online (Sandbox Code Playgroud)
程序输出如预期:
a is not a boolean.
b is a boolean.
Run Code Online (Sandbox Code Playgroud)
另外,如果我给出std::visit的实例BaseVisitor,则不会发生错误。
为什么派生类的对象CheckBooleanVisitor不被接受为有效的可调用对象std::visit?
P/s:我很确定问题的原因是上面定义中发生重写的代码CheckBooleanVisitor。但为什么 ?
函数重载(同一范围内的多个同名函数)和函数覆盖(派生类中的函数提供与基virtual类版本不同的实现)以令人不快的方式交互。
如果基类定义了具有某个名称的函数,并且派生类定义了具有相同名称的函数,则派生类将默认隐藏基类版本的所有重载。operator()也不例外。事实上,基类版本是virtual派生类的函数overriding。
因此,如果您希望通过派生类实例可以访问非重写版本,则必须显式地using使用它们:
virtual void operator()(bool) override { // WHERE THE OVERRIDING TAKES PLACE
m_isBoolean = true;
}
using BaseVisitor::operator();
Run Code Online (Sandbox Code Playgroud)