views:

259

answers:

3

I'm writing simple code that will extract a bunch of name, int pairs from a file. I'm modifying existing code that just uses:

string chrom;
unsigned int size;
while ( cin >> chrom >> size ) {
    //  save values
}

But I want to use another (similar) input file that has the same first two columns, but are followed by other data (that will be ignored). So I write:

string chrom;
unsigned int size;
string line;
while ( getline(cin, line) ) {
    if( stringstream(line) >> chrom >> size ) {
        // save values
    }
}

But this fails to compile, giving the typical obscene std lib template spew:

 error: no match for "operator>>" in "std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >(((const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)((const std::basic_string<char, std::char_traits<char>, std::allocator<char> >*)(& line))), std::operator|(_S_out, _S_in)) >> chrom"
istream:131: note: candidates are: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_istream<_CharT, _Traits>& (*)(std::basic_istream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
[...another dozen lines...]

Right. line isn't a std::string, but some variation of std::basic_string, etc. However, explicitly instantiating the stringstream works.

string chrom;
unsigned int size;
string line;
while ( getline(genome, line) ) {
    stringstream ss(line);
    if ( ss >> chrom >> size ) {
       // save values
    }
    // Discard remainder of line
}

Why? What is wrong with the first case? The example basic_io at the always helpful cplusplus.com works, why doesn't my code?

Update: Another point of reference: the temporary stringstream works when the first value extracted is an int instead of a string:

unsigned int chrom;  // works as int...
unsigned int size;
string line;
while ( getline(cin, line) ) {
    if( stringstream(line) >> chrom >> size ) {
        // save values
    }
}
+2  A: 

Some operators in C and C++ require that the value on the left of the operator be an lvalue, i.e. that they can be modified.

Here is a more complete explanation.

John Weldon
+1  A: 

Because the first value extracted from the stringstream is a std::string. If it was, say, an int, the stringstream(line) version would work.

There's no member function operator>> in stringstream for std::string. Therefore, the temporary stream cannot function as an lvalue.

Not that I fully understand the above... but perhaps it's a starting place for a better answer.

jmanning2k
+2  A: 

To expand on John Weldon's answer, the extrace operator ">>" does two things:

  1. Extracts the next value and places it into the variable on the right of the operator.
  2. Increments the current position of the stream on the left.

Therefore, it modifies both its left and right operand. In your case, the left-hand operand is a temporary value, and the compiler frowns on modifying it.

antonm
But it works fine with the temporary lvalue when the right hand operator is a int instead of a string...?
jmanning2k