2

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'

Vero
  • 313
  • 2
  • 9
  • [Cannot reproduce](https://godbolt.org/z/sjj5d3daM) – n. m. could be an AI Dec 03 '22 at 14:13
  • 1
    You have to uncomment the line ```//return process(visitable); //I need to do this but I can't. I thought this the goal!```. Could you please please delete your comment it's shadowing the issue and people will just pass by :) Thanks so much for checking! – Vero Dec 03 '22 at 14:24
  • @Vero not sure what's the problem? you can use `std::visit` to do operation, or `std::get_if` if you want to know if it's a string. – apple apple Dec 03 '22 at 14:30
  • Repro: [Link](https://godbolt.org/z/M1qscoYxE). Could you please help solve? Thanks so much! – Vero Dec 03 '22 at 14:31
  • Please do not post code that works. If you have code that does NOT work, post it with no change. Otherwise it is not clear what your problem is and I need to do an unknown number of edits in order to reproduce it. – n. m. could be an AI Dec 03 '22 at 15:56

2 Answers2

2

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();
    }
};
apple apple
  • 10,292
  • 2
  • 16
  • 36
1

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;
};
apple apple
  • 10,292
  • 2
  • 16
  • 36