0

I've been trying for the last three day to figure out how to implement a generic way of getting the value out of a boost::variant<...>, but it's been quite difficult.

Here is the solution I could come up with, which it not at all generic:

#include <iostream>
#include "boost\variant\variant.hpp"

using MyVariant = boost::variant<int, std::string>;

class VariantConverter : public boost::static_visitor<>
{
private:
    mutable int _int;
    mutable std::string _string;

    static VariantConverter apply(MyVariant& v) 
    {
        VariantConverter res;

        v.apply_visitor(res);

        return res; // copy will be elided, right?
    }

public:
    void operator()(int& i) const
    {
        _int = i;
    }

    void operator() (std::string& s) const
    {
        _string = s;
    }

    static int to_int(MyVariant v) 
    {
        return apply(v).from_int();
    }

    static std::string to_string(MyVariant v) 
    {
        return apply(v).from_string();
    }

    int from_int() 
    { 
        return _int; 
    };

    std::string from_string() 
    { 
        return _string; 
    };
};

int main()
{
    using namespace std;

    MyVariant v = 23;

    int i = VariantConverter::to_int(v);

    cout << i << endl;

    v = "Michael Jordan";

    std::string s = VariantConverter::to_string(v);

    cout << s.c_str() << endl;

    cin.get();

    return 0;
}

I'd appreciate it if someone could guide me towards a better solution.

Or perhaps someone could explain to me the rationale behind this:

if I declare a:

using MyVariant = boost::variant<int, std::string>;

and then a:

ConverterToInt : basic_visitor<int> {
public:
    int operator() (int i) { return i; };
};

Why is it that when I try to apply the ConverterToInt to a MyVariant as such:

ConverterToInt cti;

MyVariant i = 10;

i.apply_visitor(cti);

I get a compiler error about trying to find a operator() that takes a std::string?

It seems to me that apply_visitor is trying to call an operator() for each of the types MyVariant can take. Is that so? If it is, why? How can i avoid this behavior?

Cheers!

Bruno Santos
  • 724
  • 7
  • 19

2 Answers2

1

You can avoid the error message by telling ConverterToInt what to do with a std::string. You might know that i can't be a std::string but it's unreasonable to expect the compiler to know that (and if it is true, why are you using a variant?).

apply_visitor will only call the correct operator() method, but it decides at run time, and the compiler needs to have all the possibilities covered to generate the code.

rici
  • 234,347
  • 28
  • 237
  • 341
0
MyVariant iv = 10;    
int i = boost::get<int>(iv);

boost::variant does not "call" each operator() of an interface when invoked, but it must be able to. That's the entire point. A variant can hold any of the template types, so if you want to define an operation on it, you must specify somewhere what that operation means for each type.

Jeffrey Faust
  • 547
  • 3
  • 12