pseudo
pseudo

Reputation: 385

How to use Boost Variant with struct objects C++

I have two classes and depending on the nature of key, I would like to get the struct value out of the boost::variant. The code is listed below.

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

using namespace std;

class A {
    public:
    struct greeting {
        string hello;
};


class B {
    public:
    struct greeting {
        string bye;
    };
};

typedef boost::variant<A::greeting, B::greeting> greet;

greet getG(string key) {
    greet g;
    if (key == "A") {
        g.hello = "MY ENEMY"; // this line doesn't work
    }
    else {
        g.bye = "MY FRIEND"; // nor this line
    }
    return g;
};

int main() {
    A a;
    B b;
    greet h = getG("A");
    A::greeting my = boost::get<A::greeting>(h);
    cout << my.hello << endl;
    return 0;
}

The exact error that I am getting is: error: no member named 'hello' in 'boost::variant<A::greeting, B::greeting, boost::detail::variant::void_, boost::detail::variant::void_, ...>' g.hello = "MY ENEMY"; and error: no member named 'bye' in 'boost::variant<A::greeting, B::greeting, .../>' g.bye = "MY FRIEND";

Any help is appreciated.

Upvotes: 1

Views: 1750

Answers (1)

alfC
alfC

Reputation: 16270

The variant type doesn't have the .hello and .bye members. You can access them via a "visitor" function. But you still have to decide what to do when the visitor is not applied to the right type. I think you are not using Boost.Variant in the way that is intended to be used. (For example the conditionals don't smell well).

http://www.boost.org/doc/libs/1_61_0/doc/html/variant/reference.html#variant.concepts.static-visitor

struct hello_visitor : boost::static_visitor<>{
    string const& msg;
    hello_visitor(string const& msg) : msg(msg){}
    void operator()(A::greeting& t) const{
        t.hello = msg;
    }
    void operator()(B::greeting& t) const{
        // throw? ignore? other?
    }
};

struct bye_visitor : boost::static_visitor<>{
    string const& msg;
    bye_visitor(string const& msg) : msg(msg){}
    void operator()(A::greeting& t) const{
        // throw? ignore? other?
    }
    void operator()(B::greeting& t) const{
        t.bye = msg;
    }
};


greet getG(string key) {
    greet g;
    if (key == "A") { // is "key" handling the type, if so you can delegate this to the library instead of doing this.
        boost::apply_visitor(hello_visitor("MY ENEMY"), g); 
    }
    else {
        boost::apply_visitor(bye_visitor("MY FRIEND"), g); 
    }
    return g;
};

Upvotes: 2

Related Questions