Search code examples
c++templatesoperator-overloadingoverload-resolution

Cannot std::cout an implicitly converted std::string


I used to display an string by std::cout << str << std::endl, and thought an object implicitly convertabel to std::string can be also displayed in this way.

However, I notice that I was wrong. I cannot std::cout an implicitly converted std::string until I overload operator << for std::string.

The following code demonstrates the mentioned stuff.

#include <stdio.h>
#include <iostream>
#include <string>

class X
{
public:
    operator std::string() const {
        return std::string("world");
    }
};

#ifdef OVERLOAD_STREAM_OP
std::ostream& operator<<(std::ostream& os, const std::string& s) {
    return os << s;
}
#endif

int main() {
    std::string s = "hello";
    std::cout << s << std::endl; // viable
    printf("---\n");
    X x;
    std::cout << x << std::endl; // not viable

    return 0;
}

It seems that, in STL implementation, the overloaded operator << function for std::string type, is a little bit different (But I really really don't understand those template stuffs):

  template<typename _CharT, typename _Traits, typename _Allocator>
    std::basic_ostream<_CharT, _Traits>&
    operator<<(std::basic_ostream<_CharT, _Traits>& __os,
           const basic_string<_CharT, _Traits, _Allocator>& __str)
    { return __os << __str._M_base(); }

My questions:

  1. What is the difference between STL's overloaded operator << and my own overloaded operator<< for std::string type?

  2. Why I cannot display the implicitly converted std::string object x with std::cout(compile error)?


Solution

    1. What is the difference between STL's overloaded operator << and my own overloaded operator<< for std::string type?

    Your operator<< is non-template, while STL's one is template.

    1. Why I cannot display the implicitly converted std::string object x with std::cout(compile error)?

    Implicit conversion (from X to std::string) won't be considered in template argument deduction, which makes the invocation on the template operator<< failing. On the other hand, non-template operator<< doesn't have such issue.

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