By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,958 Members | 1,179 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,958 IT Pros & Developers. It's quick & easy.

std::operator<<(basic_ostream&, type) vs. std::basic_ostream::operator(type)... ?

P: n/a
Hello.

I tried to overload the operator<< for implicit printing of wchar_t
string on a char stream.
Normally using it on a ostream will succeed as
std::operator<<<std::char_traits<char>
>(std::basic_ostream<char,std::char_traits<char & _Ostr={...}, ___)
will be called.

However, I am using the boost::format library that internally makes use
of a string stream to store the formatted string. There:
std::basic_ostream<char,std::char_traits<char::ope rator<<(___)
will always be called.

On what basis will the compiler choose which kind of operator<< will be
called??

(see test code below)

thanks.
br,
Martin

test code:
###############
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

// Output wchar_t* strings on char streams instead of formatting as
void* ...
ostream& operator<<(ostream& os, const wchar_t* c_ptr) {
return os << "(TYPE:wchar_t*)"; // placeholder
}

// Boost.Format library
#include <boost/format.hpp>

////////////////////////////////////////
int main(int argc, char* argv[])
{
ostringstream ostr;
ostream& o = ostr;

o << "\nTest of ostream << operator ..." << endl;
wchar_t* wstr = L"Hello world!";
o << "Output of wchar_t* -- " << wstr << endl;
// CALL STACK ...
// (2) opov.exe!std::operator<<<std::char_traits<char>
>(std::basic_ostream<char,std::char_traits<char & _Ostr={...}, const
char * _Val=0x0042f860) Line 747 C++
// (1)
opov.exe!operator<<(std::basic_ostream<char,std::c har_traits<char &
os={...}, const wchar_t * c_ptr=0x0042f8f0) Line 6 + 0xe bytes C++
// (0) opov.exe!main(int argc=1, char * * argv=0x00356828) Line 17 +
0x26 bytes C++

o << "\nTest of boost-library ostream << operator ..." << endl;
o << "Boost formatted wchar_t* -- " << boost::str(boost::format("%1%")
% wstr) << endl;
// CALL STACK ...
// (6) msvcp80d.dll!std::basic_ostream<char,std::char_tra its<char>
>::operator<<(const void * _Val=0x00433a54) Line 456 C++
// (5)
opov.exe!boost::io::detail::put_last<char,std::cha r_traits<char>,wchar_t
*>(std::basic_ostream<char,std::char_traits<char & os={...}, wchar_t
* const & x=0x00433a54) Line 98 + 0x11 bytes C++
// (4)
opov.exe!boost::io::detail::put<char,std::char_tra its<char>,std::allocator<char>,wchar_t
* const &>(wchar_t * const & x=0x00433a54, const
boost::io::detail::format_item<char,std::char_trai ts<char>,std::allocator<char>
& specs={...},
std::basic_string<char,std::char_traits<char>,std: :allocator<char &
res="",
boost::io::basic_altstringbuf<char,std::char_trait s<char>,std::allocator<char>
& buf={...}, std::locale * loc_p=0x00000000) Line 150 + 0x2c bytes C++
// (3)
opov.exe!boost::io::detail::distribute<char,std::c har_traits<char>,std::allocator<char>,wchar_t
* const
&>(boost::basic_format<char,std::char_traits<char> ,std::allocator<char>
& self={...}, wchar_t * const & x=0x00433a54) Line 242 + 0x3f bytes C++
// (2)
opov.exe!boost::io::detail::feed<char,std::char_tr aits<char>,std::allocator<char>,wchar_t
* const
&>(boost::basic_format<char,std::char_traits<char> ,std::allocator<char>
& self={...}, wchar_t * const & x=0x00433a54) Line 251 + 0xd bytes C++
// (1)
opov.exe!boost::basic_format<char,std::char_traits <char>,std::allocator<char>
>::operator%<wchar_t *>(wchar_t * const & x=0x00433a54) Line 64 +
0xd bytes C++
// (0) opov.exe!main(int argc=1, char * * argv=0x00356828) Line 53 C++

// As can be seen on (5) the parameter (now called x) is of type wchar_t*
// However, the basic_ostream operator<<(void*) will be called.

cout << ostr.str();
}
##################
Mar 6 '08 #1
Share this Question
Share on Google+
3 Replies


P: n/a
On Mar 6, 5:38 pm, "Martin T." <0xCDCDC...@gmx.atwrote:
I tried to overload the operator<< for implicit printing of wchar_t
string on a char stream.
Normally using it on a ostream will succeed as
std::operator<<<std::char_traits<char>
>(std::basic_ostream<char,std::char_traits<char & _Ostr={...}, ___)
will be called.
However, I am using the boost::format library that internally makes use
of a string stream to store the formatted string. There:
std::basic_ostream<char,std::char_traits<char::ope rator<<(___)
will always be called.
On what basis will the compiler choose which kind of
operator<< will be called??
Overload resolution on the set of visible functions.

You have to be very careful here with user defined << operators
on basic types. When << is invoked for a standard type from
within a template, only std:: will be searched at the point of
instantiation, so if the << wasn't defined at the point of
definition, it won't be found.
(see test code below)
test code:
###############
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
// Output wchar_t* strings on char streams instead of formatting as
void* ...
ostream& operator<<(ostream& os, const wchar_t* c_ptr) {
return os << "(TYPE:wchar_t*)"; // placeholder
}
// Boost.Format library
#include <boost/format.hpp>
Except that here, you've declared (and defined, but that doesn't
matter) the operator before including the header. So even in a
template, the compiler should find your declaration, and use it.
(Unless, of course, boost::format was exported---but I get the
same results as you with g++, which doesn't support export.)

If I put the << operator in namespace std (illegal, and
undefined behavior, but you can often get away with it), the
code works (even if the declaration is moved after the include
of boost/format.hpp), but my understanding of the standard is
that this should not be necessary if the declaration precedes
the template definition (which, of course, is in the file
boost/format.hpp).

It seems weird to me, too.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Mar 7 '08 #2

P: n/a
James Kanze wrote:
On Mar 6, 5:38 pm, "Martin T." <0xCDCDC...@gmx.atwrote:
>(snipped)
>On what basis will the compiler choose which kind of
operator<< will be called??

Overload resolution on the set of visible functions.

You have to be very careful here with user defined << operators
on basic types. When << is invoked for a standard type from
within a template, only std:: will be searched at the point of
instantiation, so if the << wasn't defined at the point of
definition, it won't be found.
Ah ok. This kindof makes sense. Thanks for pointing it out explicitly.

>(see test code below)
>test code:
###############
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
>// Output wchar_t* strings on char streams instead of formatting as
void* ...
ostream& operator<<(ostream& os, const wchar_t* c_ptr) {
return os << "(TYPE:wchar_t*)"; // placeholder
}
>// Boost.Format library
#include <boost/format.hpp>

Except that here, you've declared (and defined, but that doesn't
matter) the operator before including the header. So even in a
template, the compiler should find your declaration, and use it.
(Unless, of course, boost::format was exported---but I get the
same results as you with g++, which doesn't support export.)

If I put the << operator in namespace std (illegal, and
undefined behavior, but you can often get away with it), the
code works (even if the declaration is moved after the include
of boost/format.hpp), but my understanding of the standard is
that this should not be necessary if the declaration precedes
the template definition (which, of course, is in the file
boost/format.hpp).

It seems weird to me, too.
Thanks a lot for this explanation!
I sadly had to give up further experiments for now, as my work time is
only limited atm. :/

(The reason I wanted to do this was some functions that return wchar_t*
but my logging is done in char* and in these cases I will get the
wchar_t* formatted as void*, which is obv. not what I want, but the
compiler will not find the code parts where the explicit conversion
wchar_t->char has been forgotten. (as there exists a conversion from
wchar_t* to void*) ... grml ...)
Maybe someone else can clear-up this "weirdness" as it apparently seems
to happen on g++ (you) and on MSVC8 (VS2005) (me) ...

br,
Martin
Mar 7 '08 #3

P: n/a
On 7 mar, 13:18, "Martin T." <0xCDCDC...@gmx.atwrote:
James Kanze wrote:
On Mar 6, 5:38 pm, "Martin T." <0xCDCDC...@gmx.atwrote:
(snipped)
Maybe someone else can clear-up this "weirdness" as it apparently seems
to happen on g++ (you) and on MSVC8 (VS2005) (me) ...
Yes. I'm curious myself, because it does seem to be
intentional. Maybe there's something particular in
boost::format which affects name lookup as well; I didn't have
time to search it in detail to see, but if so, I can't off hand
imagine what it could be.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Mar 7 '08 #4

This discussion thread is closed

Replies have been disabled for this discussion.