We help IT Professionals succeed at work.

Problem overloading << operator

chsalvia
chsalvia asked
on
402 Views
Last Modified: 2013-12-14
I have a class which contains a wchar_t* text buffer.  I've overloaded the << operator so I can wcout the text buffer by typing wcout and the instance of the class name.

I do this by putting the following line outside of the class:

wostream& operator << (wostream& wstrm, buffer& buf) { return wstrm << buffer.data(); }

So if I do:

buffer buf = L"Hello"
wcout << buf << endl;

...it will output properly. The function data() of course is a member function which returns the wchar_t* variable, just like the STL string data().  The problem is, if I try to output a member function which returns an instance of class buffer, the << operator does not work.

For example, say func1() returns an object of type buffer:

buffer func1()
{
      buffer buf;
      //do something with buf
      return buf;
}

If I do:

wcout << buf.func1() << endl;

...it won't compile.  Why doesn't this work?  buf.func1() returns an object of type buffer, and << is overloaded to accept objects of type buffer.

Another option I tried was to make func1 return a reference to buf.  This works if I make the object static, but that causes other problems.
Comment
Watch Question

jkr
CERTIFIED EXPERT
Top Expert 2012

Commented:
Could you post more of your code?

#include <iostream>
using namespace std;

class buffer {

public:

//wostream& operator << (wostream& wstrm, buffer& buf) { return wstrm << buf; }

char* data() { return "test";}
buffer func1()
{
     buffer buf;
     //do something with buf
     return buf;
}
};

wostream& operator << (wostream& wstrm, buffer& buf) { return wstrm << "test"; }

int main () {

buffer buf;
wcout << buf << endl;

wcout << buf.func1() << endl;

}

The above compiles without a problem
jkr
CERTIFIED EXPERT
Top Expert 2012

Commented:
Also, extending that to

buffer func2()
{
     buffer buf;
     //do something with buf
     return buf;
}

int main () {

buffer buf;
wcout << buf << endl;

wcout << buf.func1() << endl;

wcout << func2() << endl;

}

does not cause any problems. What error exactly are you getting?

Author

Commented:
Hmm...maybe this is another gcc thing.  I copied and pasted your code exactly and it didn't compile.  The error message is extremely long:

test.cpp: In function ‘int main()’:
test.cpp:26: error: no match for ‘operator<<’ in ‘std::wcout << buf. buffer::func1()’
/usr/include/c++/4.0.2/bits/ostream.tcc:67: note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>& (*)(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/bits/ostream.tcc:78: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ios<_CharT, _Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/bits/ostream.tcc:90: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/bits/ostream.tcc:125: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/bits/ostream.tcc:159: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/bits/ostream.tcc:102: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/ostream:176: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/ostream:187: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/ostream:191: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/ostream:202: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/bits/ostream.tcc:183: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/bits/ostream.tcc:218: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/bits/ostream.tcc:242: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/ostream:217: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/bits/ostream.tcc:265: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/bits/ostream.tcc:288: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/bits/ostream.tcc:311: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_streambuf<_CharT, _Traits>*) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
test.cpp:19: note:                 std::wostream& operator<<(std::wostream&, buffer&)
/usr/include/c++/4.0.2/bits/ostream.tcc:571: note:                 std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const char*) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
/usr/include/c++/4.0.2/ostream:447: note:                 std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, char) [with _CharT = wchar_t, _Traits = std::char_traits<wchar_t>]
jkr
CERTIFIED EXPERT
Top Expert 2012

Commented:
Sorry, the example should be

#include <iostream>
using namespace std;


class buffer {

public:

wchar_t* data() { return L"test";}
buffer func1()
{
     buffer buf;
     //do something with buf
     return buf;
}
};

buffer func2()
{
     buffer buf;
     //do something with buf
     return buf;
}

wostream& operator << (wostream& wstrm, buffer& buf) { return wstrm << buf.data(); }

int main () {

buffer buf;
wcout << buf << endl;

wcout << buf.func1() << endl;

wcout << func2() << endl;

}

Could you try that again?

Commented:
Do you also have a field named buf or buffer somewhere?  It looks like the compiler sees a buf.buffer somewhere!

Author

Commented:
>> Could you try that again?

No, it still doesn't compile.  It gives the same template error message.

Does it compile as is in VC?

Author

Commented:
>> Do you also have a field named buf or buffer somewhere?  It looks like the compiler sees a buf.buffer somewhere!

No, actually that error message was produced from a program containing only the code in jkr's above post, which does not include a function called buffer.  buffer is the name of the class.
jkr
CERTIFIED EXPERT
Top Expert 2012

Commented:
Compiles in both VC6 and VC7. BTW, the following

#include <iostream>
using namespace std;


class buffer {

public:

char* data() { return "test";}
buffer& func1()
{
     buffer buf;
     //do something with buf
     return buf;
}
};

     buffer buf;
buffer& func2()
{
     //do something with buf
     return buf;
}

ostream& operator << (ostream& wstrm, buffer& buf) { return wstrm << buf.data(); }

int main () {

buffer buf;
cout << buf << endl;

cout << buf.func1() << endl;

cout << func2() << endl;

}

also works with g++

Author

Commented:
jkr,

I tried compiling your code also using Borland under Windows, and it returns this (more user-friendly) error:

Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
test.cpp:
Error E2094 test.cpp 32: 'operator<<' not implemented in type 'wostream' for arg
uments of type 'buffer' in function main()
Error E2094 test.cpp 34: 'operator<<' not implemented in type 'wostream' for arg
uments of type 'buffer' in function main()
Error E2134 test.cpp 34: Compound statement missing } in function main()
*** 3 errors in Compile ***

So it can't be a gcc problem.  

Author

Commented:
>>also works with g++

Okay - I tried that and it compiled with g++.   But I had actually already tried to return a reference.  It compiles with a warning:

test.cpp: In member function ‘buffer& buffer::func1()’:
test.cpp:12: warning: reference to local variable ‘buf’ returned


Before, when I tried returning a reference I let the warning go, but sometimes it returns garbage characters.  So, to fix that I made the variable in func1() to be static - but that caused other strange problems where if I called the function multiple times with different input parameters it would return the same result as the first function call everytime.
jkr
CERTIFIED EXPERT
Top Expert 2012

Commented:
Use the 2nd example, the 1st one is buggy.
jkr
CERTIFIED EXPERT
Top Expert 2012

Commented:
>>test.cpp:12: warning: reference to local variable ‘buf’ returned

That's why I moved 'buf' out of that function (for testing purposes).

Author

Commented:
I was using the second example.  It compiles with the warning:

test.cpp: In member function ‘buffer& buffer::func1()’:
test.cpp:12: warning: reference to local variable ‘buf’ returned

I mean...it works, but it gives that warning.  Is that okay?
jkr
CERTIFIED EXPERT
Top Expert 2012

Commented:
The example for g++ is completely different - it uses 'char' instead of 'wchar_t', since my g++ here is 2.96

>>I mean...it works, but it gives that warning.  Is that okay?

No, returning a reference to a local object will most likely cause a crash at runtime.

Author

Commented:
But surely there must be some way of doing this.  I tried compiling the second example (the one posted at 09:14AM PST) in both g++ and Borland, and both returned a similar error.  And returning a reference doesn't work because it returns a local object.

I wonder why it compiles in VC?
CERTIFIED EXPERT
Top Expert 2012
Commented:
This one is on us!
(Get your first solution completely free - no credit card required)
UNLOCK SOLUTION

Author

Commented:
This seems like a strange limitation.  So, you need to make a public member variable and then assign something to it inside the function, in order to wcout to a function that returns an instance of a class?
jkr
CERTIFIED EXPERT
Top Expert 2012

Commented:
>>This seems like a strange limitation.  So, you need to make a public member variable and then assign
>>something to it inside the function, in order to wcout to a function that returns an instance of a class?

There is no public member variable in the above. Only the globbal function outside 'buffer' needs a global variable also. Or, a static one.

Gain unlimited access to on-demand training courses with an Experts Exchange subscription.

Get Access
Why Experts Exchange?

Experts Exchange always has the answer, or at the least points me in the correct direction! It is like having another employee that is extremely experienced.

Jim Murphy
Programmer at Smart IT Solutions

When asked, what has been your best career decision?

Deciding to stick with EE.

Mohamed Asif
Technical Department Head

Being involved with EE helped me to grow personally and professionally.

Carl Webster
CTP, Sr Infrastructure Consultant
Empower Your Career
Did You Know?

We've partnered with two important charities to provide clean water and computer science education to those who need it most. READ MORE

Ask ANY Question

Connect with Certified Experts to gain insight and support on specific technology challenges including:

  • Troubleshooting
  • Research
  • Professional Opinions
Unlock the solution to this question.
Join our community and discover your potential

Experts Exchange is the only place where you can interact directly with leading experts in the technology field. Become a member today and access the collective knowledge of thousands of technology experts.

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.