Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does <iostream> operator<< pick the apparently wrong overload?

Consider this code:

#include <iostream>
using namespace std;

class X {
public:
    operator const wchar_t* () const { return L"Hello"; }
};

void f(const void *) {
    wcout << L"f(const void*)\n";
}

void f(const wchar_t*) {
    wcout << L"f(const wchar_t*)\n";
}

int main() {
    X x;
    f(x);

    wcout << x;
}

The output is (compiled with the VS2015 C++ compiler):

f(const wchar_t*)
00118B30

So it seems that the compiler selects the expected const wchar_t* overload for f (as there's an implicit conversion from X to const wchar_t*).

However, it seems that wcout << x picks the const void* overload, instead of the const wchar_t* one (printing an address, instead of a wchar_t string).

Why is this?

P.S. I know that the proper way of printing X is to implement an overload of operator<< like wostream& operator<<(wostream& , const X&), but that is not the point of the question.

like image 885
Mr.C64 Avatar asked Jul 28 '17 16:07

Mr.C64


1 Answers

Because when deducing template arguments the conversion functions are not considered:

// Non-template member function.
basic_ostream& basic_ostream::operator<<( const void* value );

// Template non-member function.
template< class CharT, class Traits >
basic_ostream<CharT,Traits>& operator<<( basic_ostream<CharT,Traits>& os, 
                                         const CharT* s );

The second declaration does not consider the conversion operator const wchar_t* () const.

I cannot find the standard quote, cppreference Template argument deduction, Implicit conversions says:

Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.

like image 135
Maxim Egorushkin Avatar answered Sep 28 '22 07:09

Maxim Egorushkin