9

I'm trying to read a single character from a stream. With the following code I get a "ambiguous overload" compiler error (GCC 4.3.2, and 4.3.4). What I'm doing wrong?

#include <iostream>
#include <sstream>

int main()
{
    char c;
    std::istringstream("a") >> c;
    return 0;
}

Remarks:

  • Visual Studio 2008 compiles without errors
  • Other types (int, double) are working
  • If I first create a variable std::istringstream iss("a"); iss >> c, the compiler gives no error
Christian Ammer
  • 7,464
  • 6
  • 51
  • 108

2 Answers2

9

The extraction operator >> for characters is a non-member function template:

template<class charT, class traits>
  basic_istream<charT,traits>& operator>>(basic_istream<charT,traits>&, charT&);

Since this takes its first argument by non-const reference, you can't use a temporary rvalue there. Therefore, your code cannot select this overload, only the various member function overloads, none of which match this usage.

Your code is valid in C++11, because there is also an extraction operator taking an rvalue reference as the first argument.

Visual Studio 2008 compiles without errors

One of that compiler's many non-standard extensions is to allow temporary rvalues to be bound to non-const references.

Other types (int, double) are working

Most extraction operators for fundamental types are member functions, which can be called on a temporary rvalue.

If I first create a variable std::istringstream iss("a"); iss >> c, the compiler gives no error

iss is a non-temporary lvalue, so it can be bound to a non-const reference.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • I remember that visual studio has extension which can bind rvalue to non-const lvalue ref , but that extension gives warning in VS which is ignored by asker I guess. Anyways +1 for such a nice answer :) – Mr.Anubis Jan 25 '12 at 14:33
  • @Mr.Anubis: I don't get a warning for this program. I don't get a warning for `std::istringstream& ss = std::istringstream("a");` either – Lightness Races in Orbit Jan 25 '12 at 14:41
  • @Mr.Anubis: After your comment I compiled it again with no warnings! But after changing the warning level from `/W3` (which seems to be default) to `/W4` I got a such warning. – Christian Ammer Jan 25 '12 at 14:42
  • @ChristianAmmer: Okie doke. That's a shame. Silly MSVC. That code should warn on the _lowest_ level! – Lightness Races in Orbit Jan 25 '12 at 14:43
  • @LightnessRacesinOrbit: it depends if you favor pedantry over pragmatism. The code works, it's just non-portable. I suppose there exist a specific portability switch equivalent to `-pedantic` that would diagnose those cases. – Matthieu M. Jan 25 '12 at 15:03
  • @MatthieuM.: What would be pragmatic is if Microsoft weren't encouraging people to write unportable code -- we're not exactly talking about crazy edge-case code here. As you can see from this question, it's led to this individual not knowing something that's quite basic in C++. Pedantry has nothing to do with this whatsoever. – Lightness Races in Orbit Jan 25 '12 at 15:06
  • @LightnessRacesinOrbit Is it worth pointing out that binding a reference to an rvalue was legal in the original C++, but that it was removed because it turned out to be too error prone. Pre-1990, so it's not like Microsoft hasn't had the time to catch up. – James Kanze Jan 25 '12 at 15:57
  • @JamesKanze: I personally consider that it is more error-prone now, sytnax wise. The inconsistency is jarring. 1. The const/non-const shism is annoying. 2. You can invoke a non-const method on a temporary, but cannot pass it as a parameter by reference --> but idiomatic C++ encourages free-functions! I would favor a more principled approach: either you can or cannot. For all its faults MSVC is at least consistent here. Though I personally favor avoiding taking references (other than r-value references) to temporaries. – Matthieu M. Jan 25 '12 at 16:14
  • @MatthieuM. Your personal considerations aren't in agreement with actual experience:-). One may argue that calling a non-const member function on an rvalue should be banned as well---that would, at least, restore symmetry. And one can definitely argue that overloading between members and free functions is not a good idea---it would be trivial to make all of the `<<` non-members, and it would be just as easy today (but not when iostream was being developed) to make them all specializations of a member function template. – James Kanze Jan 25 '12 at 16:22
  • @JamesKanze: Getting rid of `2.` is already a good step. As for 1., it was necessary to emulate operators, but now that we have r-value references operators we rewrite most operators to take advantage of it (when performance matter) anyway. – Matthieu M. Jan 25 '12 at 16:41
4

The signature for the operator>> reading a char is

template<class charT, class traits>
basic_istream<charT,traits>& operator>>(basic_istream<charT,traits>& in,charT& c);

According to the language rules, a temporary cannot bind to the first parameter as a temporary cannot bind to a non-const reference.

Visual Studio 2008 allows this as an MS extension. Later versions will warn you that it is not allowed.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203