Why doesn't implicit conversion work with wide ostream?

M

Martin Ba

Question @ SO:
http://stackoverflow.com/questions/17486156/why-doesnt-implicit-conversion-work-with-wide-ostream

I have some behaviour that I do not understand. I observed this on
VS2005, but [IDEONE (using GCC 4.7.2) outputs][http://ideone.com/doSHvq]
basically the same.

Here's the code:

#include <iostream>
#include <string>

struct UserString {
const char* p;
operator const char*() const {
std::cout << "! " << __FUNCTION__ << std::endl;
return p;
}

UserString()
: p ("UserString")
{ }
};

struct WUserString {
const wchar_t* p;
operator const wchar_t*() const {
std::cout << "! " << __FUNCTION__ << std::endl;
return p;
}

WUserString()
: p (L"WUserString")
{ }
};


int main() {
using namespace std;
cout << "String Literal" << endl;
cout << string("std::string") << endl;
cout << UserString() << endl;
cout << static_cast<const char*>(UserString()) << endl;

wcout << L"WString Literal" << endl;
wcout << wstring(L"std::wstring") << endl;
wcout << WUserString() << endl;
wcout << static_cast<const wchar_t*>(WUserString()) << endl;

return 0;
}

Here's the output:

String Literal
std::string
! operator const char* **** "works"
UserString ****
! operator const char*
UserString
WString Literal
std::wstring
! operator const wchar_t* **** "doesn't" - op<<(void*) is used
0x80491b0 ****
! operator const wchar_t*
WUserString


What's going on here?!?


cheers,
Martin
 
V

Victor Bazarov

Question @ SO:
http://stackoverflow.com/questions/17486156/why-doesnt-implicit-conversion-work-with-wide-ostream


I have some behaviour that I do not understand. I observed this on
VS2005, but [IDEONE (using GCC 4.7.2) outputs][http://ideone.com/doSHvq]
basically the same.

Here's the code:

#include <iostream>
#include <string>

struct UserString {
const char* p;
operator const char*() const {
std::cout << "! " << __FUNCTION__ << std::endl;
return p;
}

UserString()
: p ("UserString")
{ }
};

struct WUserString {
const wchar_t* p;
operator const wchar_t*() const {
std::cout << "! " << __FUNCTION__ << std::endl;
return p;
}

WUserString()
: p (L"WUserString")
{ }
};


int main() {
using namespace std;
cout << "String Literal" << endl;
cout << string("std::string") << endl;
cout << UserString() << endl;
cout << static_cast<const char*>(UserString()) << endl;

wcout << L"WString Literal" << endl;
wcout << wstring(L"std::wstring") << endl;
wcout << WUserString() << endl;
wcout << static_cast<const wchar_t*>(WUserString()) << endl;

return 0;
}

Here's the output:

String Literal
std::string
! operator const char* **** "works"
UserString ****
! operator const char*
UserString
WString Literal
std::wstring
! operator const wchar_t* **** "doesn't" - op<<(void*) is used
0x80491b0 ****
! operator const wchar_t*
WUserString


What's going on here?!?

There are several versions of op<< that compiler looks at. Some are
functions, some are function templates. There is a significant
difference between how they are treated by the compiler to figure out
which one to call and with what argument. One rule plays the most
significant role here, I think, -- the user-defined conversions are not
considered for deducing the types of template arguments (when such
deduction is needed). If the compiler is unable to find a suitable
template and deduce the type of the arguments, it stops looking at the
templates and goes on to look at overloaded functions. Not as simple
(or as straightforward) as one might want it to be...

V
 
M

Martin Ba

Question @ SO:
http://stackoverflow.com/questions/17486156/why-doesnt-implicit-conversion-work-with-wide-ostream



I have some behaviour that I do not understand. I observed this on
VS2005, but [IDEONE (using GCC 4.7.2) outputs][http://ideone.com/doSHvq]
basically the same.

Here's the code:
...
Here's the output:

String Literal
std::string
! operator const char* **** "works"
UserString ****
! operator const char*
UserString
WString Literal
std::wstring
! operator const wchar_t* **** "doesn't" - op<<(void*) is used
0x80491b0 ****
! operator const wchar_t*
WUserString


What's going on here?!?

There are several versions of op<< that compiler looks at. Some are
functions, some are function templates. There is a significant
difference between how they are treated by the compiler to figure out
which one to call and with what argument. One rule plays the most
significant role here, I think, -- the user-defined conversions are not
considered for deducing the types of template arguments (when such
deduction is needed). If the compiler is unable to find a suitable
template and deduce the type of the arguments, it stops looking at the
templates and goes on to look at overloaded functions. Not as simple
(or as straightforward) as one might want it to be...

Thanks.

What I find rather strange is that the char version seems to work
differently from the wchar_t version (in both GCC 4.7 as well as VS2005).

Since I'd have thought that both would be typedefs for the same template
class (basic_ostream), I'm really confused as to the difference.

br,
Martin
 
V

Victor Bazarov

Question @ SO:
http://stackoverflow.com/questions/17486156/why-doesnt-implicit-conversion-work-with-wide-ostream




I have some behaviour that I do not understand. I observed this on
VS2005, but [IDEONE (using GCC 4.7.2) outputs][http://ideone.com/doSHvq]
basically the same.

Here's the code:
...
Here's the output:

String Literal
std::string
! operator const char* **** "works"
UserString ****
! operator const char*
UserString
WString Literal
std::wstring
! operator const wchar_t* **** "doesn't" - op<<(void*) is used
0x80491b0 ****
! operator const wchar_t*
WUserString


What's going on here?!?

There are several versions of op<< that compiler looks at. Some are
functions, some are function templates. There is a significant
difference between how they are treated by the compiler to figure out
which one to call and with what argument. One rule plays the most
significant role here, I think, -- the user-defined conversions are not
considered for deducing the types of template arguments (when such
deduction is needed). If the compiler is unable to find a suitable
template and deduce the type of the arguments, it stops looking at the
templates and goes on to look at overloaded functions. Not as simple
(or as straightforward) as one might want it to be...

Thanks.

What I find rather strange is that the char version seems to work
differently from the wchar_t version (in both GCC 4.7 as well as VS2005).

Since I'd have thought that both would be typedefs for the same template
class (basic_ostream), I'm really confused as to the difference.

I subscribe to the same confusion, Martin. The explanation might be in
the fact that the op<< for outputting const char* is a non-template,
just like the op<< for const void*, which are probably both present in
the set of the overloaded functions. So, when it fails to lock onto the
template, it looks for the best among the non-template ones. For
outputting the const char* it finds the exact match and for outputting
the const wchar_t* it has to go with const void*... But take it with a
pinch of salt, I haven't followed all the steps thoroughly.

V
 
M

Martin Ba

Question @ SO:
http://stackoverflow.com/questions/17486156/why-doesnt-implicit-conversion-work-with-wide-ostream


I have some behaviour that I do not understand. I observed this on
VS2005, but [IDEONE (using GCC 4.7.2) outputs][http://ideone.com/doSHvq]
basically the same.


What's going on here?!?

Answer from SO: (quoting Bo Persson)
+ + + + begin quote + + + +
There is a partial specialization for basic_ostream

template<class _TraitsT>
basic_ostream<char, _TraitsT>&
operator<<(basic_ostream<char, _TraitsT>& _Stream, const char*
_String);

which is a good fit for the `cout << UserString()` case.

There is nothing similar for `wchar_t` and `WUserString()`, so the
member function

basic_ostream& operator<<(const void* _Address);

will be the best match for that (as in most "unusual" cases).
+ + + + end quote + + + +

As far as I'm concerned, it would seem that this is just another
iostream insanity. :-/

br,
Martin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top