3

I was going through boost::variant and wondering how can I make following to work ?

typedef boost::variant<int,std::string> myval;
int main()
{

std::vector<myval> vec;

std::ifstream fin("temp.txt");

//How following can be achieved ?
std::copy(std::istream_iterator<myval>(fin), //Can this be from std::cin too ?
          std::istream_iterator<myval>(),
          std::back_inserter(vec));   
}

For classes data members we have option to overload >> operator, but how to do this with myval ?

Igor R.
  • 14,716
  • 2
  • 49
  • 83
P0W
  • 46,614
  • 9
  • 72
  • 119

2 Answers2

3

You can overload operator>> for variant just like for any other type. But it is up to you to implement the logic to decide what type is read from the stream and stored in variant. Here's a complete example of how you might go about it:

#include "boost/variant.hpp"
#include <iostream>
#include <cctype>
#include <vector>
#include <string>

typedef boost::variant<int, std::string> myval;

namespace boost { // must be in boost namespace to be found by ADL
std::istream& operator>>(std::istream& in, myval& v)
{
    in >> std::ws;      // throw away leading whitespace
    int c = in.peek();
    if (c == EOF) return in;  // nothing to read, done

    // read int if there's a minus or a digit
    // TODO: handle the case where minus is not followed by a digit
    // because that's supposed to be an error or read as a string
    if (std::isdigit(static_cast<unsigned char>(c)) || c == '-') {
        int i;
        in >> i;
        v = i;
    } else {
        std::string s;
        in >> s;
        v = s;
    }
    return in;
}
} // namespace boost

// visitor to query the type of value
struct visitor : boost::static_visitor<std::string> {
    std::string operator()(const std::string&) const
    {
        return "string";
    }
    std::string operator()(int) const
    {
        return "int";
    }
};

int main()
{
    std::vector<myval> vec;
    std::copy(
        std::istream_iterator<myval>(std::cin),
        std::istream_iterator<myval>(),
        std::back_inserter(vec));

    std::cout << "Types read:\n";
    for (const auto& v : vec) {
        std::string s = boost::apply_visitor(visitor(), v);
        std::cout << s << '\n';
    }
}

Example input: 1 2 3 hello 4 world

Output:

Types read:
int
int
int
string
int
string
jrok
  • 54,456
  • 9
  • 109
  • 141
  • that's really nice way. But for some reason I get all as `string` . I'm using MingW 4.7.2 – P0W Aug 02 '13 at 08:36
  • @P0W You mean all strings in output? Even if you input integers and with the exact code I posted? – jrok Aug 02 '13 at 08:41
  • @P0W Nevermind, there was a silly mistake in `if` statement, fixed. – jrok Aug 02 '13 at 08:44
0

myval is just a type. You overload operators based on types.

std::istream &operator >>(std::istream &stream, myval &val)
{
    //Put stuff here.
}

As for what to put there, that's entirely up to you and what you expect or require there to be in the stream.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 3
    Will this operator participate in the name look-up? I'm afraid you have to put it in either `boost` or `std` namespace. – Igor R. Aug 02 '13 at 08:11
  • @NicolBolas `std::istream &operator >>(std::istream &stream, myval &val) { return stream>>val; }` doesn't compile. However `myval x; std::cin>>x;` compiles (after overloading) but the executable crashes – P0W Aug 02 '13 at 08:20
  • @NicolBolas, thanks, now I get what you were trying to say by correlating with jrok's example – P0W Aug 02 '13 at 08:40