Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why cannot use cout with user-defined conversion to std::string?

Here I define a Date, and specify a user-defined conversion.

class Date {
private:
    int day;
    int month;
    string dateStr;
public:
    Date(int _day, int _month) : day(_day), month(_month) {}

    operator const string() {
        ostringstream formattedDate;
        formattedDate << month << "/" << day;
        dateStr = formattedDate.str();
        return dateStr;
    }
};

It works well when converting to string.

Date d(1, 1);
string s = d;

But why cannot use it with cout directly?

cout << d << endl; // The compiler complains that there is no suitable type marching << operator

However, if I use char* instead of string for user-defined conversion, I can use it with cout directly. Why?

operator const char*() { 
    ostringstream formattedDate;
    formattedDate << month << " / " << day;
    dateStr = formattedDate.str();
    return dateStr.c_str();
}

ps. I know that overloading << directly will work well for output. But my question is: why cannot use << with user-defined conversion to std::string?

like image 390
chenzhongpu Avatar asked Mar 24 '17 08:03

chenzhongpu


People also ask

Why is cout not working in C++?

This may happen because std::cout is writing to output buffer which is waiting to be flushed. If no flushing occurs nothing will print. So you may have to flush the buffer manually by doing the following: std::cout.

Can you cout a string in C++?

The std::cout ObjectStd::cout is the preferred way to print a string in C++.

Why can't I use cout?

You need to put it in a function. You need to #include <string> before you can use the string class and iostream before you use cout or endl . string , cout and endl live in the std namespace, so you can not access them without prefixing them with std:: unless you use the using directive to bring them into scope first.

Why is cout so slow?

As for why it is so "time consuming", (in other words, slow,) that's because the primary purpose of std::cout (and ultimately the operating system's standard output stream) is versatility, not performance.


1 Answers

Note that std::string is an instantiation from template std::basic_string, the signature of operator<< for std::string is indeed:

template <class CharT, class Traits, class Allocator>
std::basic_ostream<CharT, Traits>& 
    operator<<(std::basic_ostream<CharT, Traits>& os, 
               const std::basic_string<CharT, Traits, Allocator>& str);

then for cout << d;, the template parameter of std::basic_string has to be deduced; but type deduction does not consider implicit conversions;

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

That means the deduction would fail; then no candidate function is viable.

But operator<< for const char* hasn't such kind of problem; implicit conversion takes effect and then works fine.

To solve the issue, you can use explicit conversion to avoid template argument deduction; or overload operator<< on the type Date directly.

like image 154
songyuanyao Avatar answered Nov 10 '22 00:11

songyuanyao