Reputation: 153
I am trying to use std::visit
to inspect an std::variant
.
First I declare the variant and a base (callable) visitor class for the 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&) {}
};
Second, I define another visitor class that derives from the base one above:
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;
}
};
I use this "derived" visitor class to visit a variant like this:
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;
}
And the compiler (VS 2022) complains in LINE #1
and LINE #2
as follows:
no instance of function template "std::visit" matches the argument list
However, if I try:
std::visit((BaseVisitor&)c, a); // LINE #1
std::visit((BaseVisitor&)c, b); // LINE #2
the program outputs as expected:
a is not a boolean.
b is a boolean.
Also, if I give std::visit
an instance of BaseVisitor
, no errors occur.
Why an object of the derived class CheckBooleanVisitor
is not accepted as a valid callable for std::visit
?
P/s: I'm quite sure the cause of the problem is the code WHERE THE OVERRIDING TAKES PLACE in the definition of CheckBooleanVisitor
above. But why ?
Upvotes: 3
Views: 325
Reputation: 473407
Function overloading (multiple functions of the same name in the same scope) and function overriding (a function in a derived class that provides a different implementation from a virtual
base class version) interact in unpleasant ways.
If a base class defines a function with some name, and a derived class defines a function with that same name, the derived class will by default hide all overloads of the base class version. operator()
is not an exception to this rule. Nor is the fact that the base class version is a virtual
function that the derived class is overriding
.
Therefore, if you want the non-overridden versions to be accessible through a derived class instance, you must explicitly using
them:
virtual void operator()(bool) override { // WHERE THE OVERRIDING TAKES PLACE
m_isBoolean = true;
}
using BaseVisitor::operator();
Upvotes: 6