Could you please help me figure out why is this not working i.e. refering to the comment in the code //I need to do this but I can't. I thought this the goal!
? I have no idea why this is not working, it's inspired by examples I have seen online.
#include <variant>
#include <iostream>
template<typename... args>
class Visitor //: public boost_base_visitor<double>...
{
public:
virtual ~Visitor() = default;
virtual double visit(typename std::variant<args...> visitable)
{
auto op = [this](typename std::variant<args...> visitable) -> double { return this->apply(visitable); };
return std::visit(std::ref(op), visitable);
}
virtual double apply(typename std::variant<args...> visitable) = 0;
Visitor() = default;
};
class SubVisitor : public Visitor<std::string, double>
{
public:
virtual ~SubVisitor() = default;
SubVisitor() : Visitor<std::string, double>() {};
virtual double apply(std::variant<std::string, double> visitable) override
{
//return process(visitable); //I need to do this but I can't. I thought this the goal!
return process(std::get<std::string>(visitable)); //I DON'T KNOW IF THIS IS REALLY A STRING??
};
virtual double process(std::string visitable)
{
std::cout << "STRING HANDLED" << std::endl;
return 0.0;
}
virtual double process(double visitable)
{
std::cout << "DOUBLE HANDLED" << std::endl;
return 1.0;
}
};
int main(int argc, char* argv[])
{
SubVisitor v;
v.apply("dd");
//v.apply(1.0); //This will fail as we only handle string?? What is the purpose of variant then?
return 1;
}
I am getting error when uncommenting the process
function above:
Error C2664: 'double SubVisitor::process(std::string)': cannot convert argument 1 from 'std::variantstd::string,double' to 'std::string'
CodePudding user response:
you can use std:visit
to operate on the variant
class SubVisitor{
virtual double apply(std::variant<std::string, double> visitable) override
{
// std::visit expect `operator()`, not `process`
// so wrap `this` inside a lambda here
return std::visit(
[this](auto&& v){return process(v);},
visitable
);
};
}
or if you want, you can also check the type manually
class SubVisitor{
virtual double apply(std::variant<std::string, double> visitable) override
{
if(auto* s = std::get_if<std::string>(&visitable))
return process(*s);
else if(auto* d = std::get_if<double>(&visitable))
return process(*d);
throw std::bad_variant_access();
}
};
CodePudding user response:
in addition to the answer, imo the base class should be something like
template<typename... args>
class Visitor{
public:
Visitor() = default;
virtual ~Visitor() = default;
// this should be non-virtual
double visit(std::variant<args...> visitable)
{
// dispatch via the customization point `this->apply`
return this->apply(visitable);
}
virtual double apply(std::variant<args...> visitable) = 0;
};