Question

typedef boost::variant<int, double> Type;
class Append: public boost::static_visitor<>
{
public:
    void operator()(int)
    {}

    void operator()(double)
    {}

};

Type type(1.2);
Visitor visitor;
boost::apply_visitor(visitor, type);

Is it possible to change the visitor such that it receives extra data as follows:

class Append: public boost::static_visitor<>
{
public:
    void operator()(int, const std::string&)
    {}

    void operator()(double, const std::string&)
    {}
};

This string value changes during the lifetime of the Append object. Passing the string in via the constructor is not an option in this case.

Was it helpful?

Solution

The "additional argument" that gets given to each call is the this pointer. Use it to pass whatever additional information that you need:

#include <boost/variant.hpp>
typedef boost::variant<int, double> Type;
class Append: public boost::static_visitor<>
{
public:
    void operator()(int)
    {}

    void operator()(double)
    {}
    std::string argument;
};

int main() {
    Type type(1.2);
    Append visitor;
    visitor.argument = "first value";
    boost::apply_visitor(visitor, type);
    visitor.argument = "new value";
    boost::apply_visitor(visitor, type);
}

OTHER TIPS

Another option is to bind the extra arguments. You visitor class could look like this:

class Append: public boost::static_visitor<>
{
public:
    void operator()(const std::string&, int)
    {}

    void operator()(const std::string&, double)
    {}
};

Call it like so:

std::string myString = "foo";
double value = 1.2;
auto visitor = std::bind( Append(), myString, std::placeholders::_1 );
boost::apply_visitor( visitor, value );

This one solves your problem:

#include <iostream>
#include <string>
#include <boost/variant.hpp>

typedef boost::variant<int, double> Type;
typedef boost::variant<const std::string> Extra;
class Append: public boost::static_visitor<>
{
public:
    void operator()(const int& a1, const std::string& a2) const {
        std::cout << "arg 1 = "<< a1 << "\n";
        std::cout << "arg 2 = "<< a2 << "\n";
    }

    void operator()(const double& a1, const std::string& a2) const {
        std::cout << "arg 1 = "<< a1 << "\n";
        std::cout << "arg 2 = "<< a2 << "\n";
    }
};

int main()
{
    Type type(1.2);
    Extra str("extra argument");
    boost::apply_visitor(Append(), type, str);
}

Here is a working Demo. You can send extra arguments - as many as you want. The restriction is that they must be wrapped inside boost::variant. However the compiler optimizes away the variants with single type inside. If you want more than two arguments you have to #include <boost/variant/multivisitors.hpp>, see https://www.boost.org/doc/libs/1_70_0/doc/html/boost/apply_visitor.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top