5

My question would have a boolean answer: yes or not. Whichever it would be, can someone explain how the following code is compiled by both GNU-g++ 4.9.2 and clang 3.5, while GNU-g++ 5.1.1 no longer accepts it, claiming that there is no matching operator==?

And how it could be changed, for this last compiler, in order to have the same results i.e. to have the operator>> able to distinguish, in such a simple way, whether it is called by the standard input stream or by something else?

  # include <iostream>
  # include <fstream>

  struct S {};

  std::istream& operator >> (std::istream& i, S& s)
   {
    if(i == std::cin) std::clog << "this is standard input\n";
    else std::clog << "this is some other input stream\n";

    return i;
    }

  int main(int narg, const char ** args)
   {
    S s;
    std :: cin >> s;
    std::ifstream inp(args[1]);
    inp >> s;
    }
  // to be executed with the name of an existing
  // disk file on the command line....
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
GSi
  • 649
  • 3
  • 10
  • Possible duplicate of [How to compare two std::istream references?](http://stackoverflow.com/questions/18868060/how-to-compare-two-stdistream-references) – MicroVirus Nov 16 '15 at 13:45
  • I don't understand what equality between streams could possibly mean. Identity, sure, but you have `&` for that. – Lightness Races in Orbit Nov 16 '15 at 14:07
  • 1
    @LightnessRacesinOrbit: A reasonable (but completely hypothetical) example would be two `fstream`s comparing equal iff they access the same file. – MSalters Nov 16 '15 at 14:45
  • 2
    @MSalters: I don't think that would make sense. You're comparing just one property of a vastly more complex entity. What about buffers? Flags? I/O modes? Cursors? – Lightness Races in Orbit Nov 16 '15 at 15:11

2 Answers2

6

No. There's no operator== that operates on std::istream objects.

Your being able to compare two std::istreams is an unfortunate consequence caused by the conversion function of std::istream, specifically operator void*. In the expression i == std::cin, both i and std::cin are implicitly converted to void*, and the resulting values are compared. This is not really meaningful. This conversion function was removed in C++11 (replaced by an explicit conversion function, which won't be called in this situation), so if you enable the C++11 mode, the code will not compile.

As is stated here, if you want to check whether the reference i refers to std::cin, you can use &i == &std::cin.

Community
  • 1
  • 1
cpplearner
  • 13,776
  • 2
  • 47
  • 72
2

Standard C++ streams don't have ==, >, < operators because they are not very meaningful in that context: what should "stream a is > than stream b" mean?

However, it shouldn't matter what type of istream you're dealing with: as long as you're not using specific methods defined in descendant classes (like is_open), base methods are shared (extracting, for instance). Whether you're extracting a string from a istringstream or a ifstream, you just do in >> str and let polymorphism take action.

If you really want to know the polymorphic type of the istream, you can use typeid or, simply, function overloading. In your case, with RTTI(typeid)

if ( typeid(in) == typeid(std::cin) )
    // cin
else
   // another istream type

Using overloading:

std::istream& operator >> (std::istream& i, S& s)
{
     std::clog << "this is standard input\n";   
     return i;
}

std::ifstream& operator>>(std::ifstream& i, S& s)
{
     std::clog << "this is some file input stream\n";
     return i;
}
edmz
  • 8,220
  • 2
  • 26
  • 45