6

I have the following code:

struct simple
{
    simple (int a1, int a2) : member1(a1), member2(a2) {}
    int member1;
    int member2;
};

std::ofstream &operator << (std::ofstream &f, const simple &obj)
{
    f<<obj.member1<<", "<<obj.member2;
    return f;
} 
int main(int argc, const char *argv[])
{
    std::ofstream f("streamout.txt");

    simple s(7,5);
    f << s;               //#1 This works
    f << "label: " << s;  //#2 This fails

    return 0;
}

I'm trying to understand why #1 works, while there are problems when trying to use the overloaded operator concatenating it as in #2 which fails with the following error (gcc 4.5.3 on MacOSX):

error: cannot bind 'std::basic_ostream' lvalue to 'std::basic_ostream&&' /GCC-FACTORY/4.5/INSTALL/lib/gcc/x86_64-apple-darwin10.5.0/4.5.3/../../../../include/c++/4.5.3/ostream:579:5: error: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char, _Traits = std::char_traits, _Tp = simple]'

Everything is instead fine if I define my operator as

std::ostream &operator << (std::ostream &f, const simple &obj)
{ ... }

Sounds like something related to overload resolution, where having a something inserted in the ofstream for which there's already a provided overload (the const char * "label" in this case) breaks up following overload resolution, but I can't really understand what exactly is going on here. I'd like to get a clear picture of what the compiler's trying to do..

skaffman
  • 398,947
  • 96
  • 818
  • 769
abigagli
  • 2,769
  • 4
  • 29
  • 32
  • 1
    I don't know specifically why the compiler complains, but overloading for `ostream` (i.e. the common base class) is the correct thing to do, as it allows it to be used for all sorts of output streams. – Oliver Charlesworth Jan 09 '11 at 18:47

1 Answers1

17

On the line :

f << "label: " << s;

Because the first call to operator<< returns a std::ostream &, the second fails to compile : the left operand to the operator is not of type std::ofstream anymore and your overload is not found.

You should really use the second signature, as I see no reason for restricting your type to be outputted to std::ofstream.

icecrime
  • 74,451
  • 13
  • 99
  • 111
  • 2
    You can farther generalize the function to work with any character traits if you use the signature `template std::basic_ostream& operator<<(std::basic_ostream& s, const simple& obj);` – wilhelmtell Jan 09 '11 at 19:30