C++ Using classes with boost::lexical_cast
Asked Answered
S

1

9

I want to use my Test class with boost::lexical_cast. I have overloaded operator<< and operator>> but It gives me runtime error.
Here is my code:

#include <iostream>
#include <boost/lexical_cast.hpp>
using namespace std;

class Test {
    int a, b;
public:
    Test() { }
    Test(const Test &test) {
        a = test.a;
        b = test.b;
    }
    ~Test() { }

    void print() {
        cout << "A = " << a << endl;
        cout << "B = " << b << endl;
    }

    friend istream& operator>> (istream &input, Test &test) {
        input >> test.a >> test.b;
        return input;
    }

    friend ostream& operator<< (ostream &output, const Test &test) {
        output << test.a << test.b;
        return output;
    }
};

int main() {
    try {
        Test test = boost::lexical_cast<Test>("10 2");
    } catch(std::exception &e) {
        cout << e.what() << endl;
    }
    return 0;
}

Output:

bad lexical cast: source type value could not be interpreted as target

Btw I'm using Visual Studio 2010 But I've tried Fedora 16 with g++ and got the same result!

Seneschal answered 30/4, 2012 at 11:24 Comment(2)
Interesting question, can't find the real answer so far. Looks like something is wrong with the stream: 1. because when it get into the stream operator, only a get updated, b is not. I added another string to check if the space was badly interpreted but even the string wasn't updated. 2. it throws when you get out of the operator , it checks something I don't understand then decide to throw.Sweeting
You should probably use the defaulted versions of the default constructor, copy constructor and destructor, instead of defining them yourself: the compiler will generate them for you (and will do so more correctly in the case of you copy constructor (see this faq).Aerotherapeutics
A
8

Your problem comes from the fact that boost::lexical_cast does not ignore whitespaces in the input (it unsets the skipws flag of the input stream).

The solution is to either set the flag yourself in your extraction operator, or just skip one character. Indeed, the extraction operator should mirror the insertion operator: since you explicitely put a space when outputting a Test instance, you should explicitely read the space when extracting an instance.

This thread discusses the subject, and the recommended solution is to do the following:

friend std::istream& operator>>(std::istream &input, Test &test)
{
    input >> test.a;
    if((input.flags() & std::ios_base::skipws) == 0)
    {
        char whitespace;
        input >> whitespace;
    }
    return input >> test.b;
} 
Aerotherapeutics answered 30/4, 2012 at 12:2 Comment(3)
+1: I just found it myself after 10 minutes of searching what the hell was happening...Sweeting
It worked, Thanks! But why did they do this? I just found out boost::lexical_cast<int>(" 123") throws the same exception!Seneschal
This question has been discussed at length on the Boost forums. This thread is quite interesting in this regard.Aerotherapeutics

© 2022 - 2024 — McMap. All rights reserved.