SwiftMango
SwiftMango

Reputation: 15284

Implicit type conversion is not working

class Test {
public:
    operator string() {
        return string{"TEST!"};
    }
};

int main() {
    cout << Test{};
}

I was expecting the Test object will be implicit converted to a string and output, but it gives me error:

error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'

This explicit conversion works:

cout << string{Test{}};

I got it working by casting to const char*:

class Test {
public:
    operator const char*() {
        return "TEST!";
    }
};

Then output:

cout << Test{}; //Yay it works.

I am assuming the cout << string is already an implicit conversion from string to char * and if I use casting to string, it will not perform a two level conversion from Test to string to char *. After directly casting to const char*, it works. (Please correct if the assumption is wrong)


TO PROVE THE ASSUMPTION IS RIGHT

class Test {
public:
    operator string() {
        return string{"TEST!"};
    }
};

ostream& operator<< (ostream& os, string s){
    os << s;
    return os;
}

This will perform a direct type deduction from Test to string and output string. and after I tried, it works!

cout << Test{}; //YAY WORKS! OUTPUT "TEST!"

Something special about cout << string is explained by Borgleader. Assumption is partially correct and partially wrong.

Upvotes: 1

Views: 1080

Answers (2)

Borgleader
Borgleader

Reputation: 15916

The explicit keyword means you have to explicitly do the conversion yourself like std::string(Test{}). It disables implicit conversions.

cout << string{Test{}}; // <-- this is explicit, you've got implicit and explicit confused

The rule is, during template argument deduction, no user defined conversion is attemped. However, as you've noted if you only have a conversion operator to int it compiles. That is because that overload is not a function template. Take a look at the reference page, and you will see:

basic_ostream& operator<<( int value );

This is a non-templated overload so the compiler will look for user defined conversions.

Upvotes: 4

Praetorian
Praetorian

Reputation: 109119

The operator<< overload that takes an std::string (or std::basic_string) is a function template. User defined conversions are not considered during template argument deduction, so the compiler doesn't think the string overload is a match.

To avoid the error, define an overload basic_ostream& operator<<(basic_ostream&, Test&) for your class.

Upvotes: 2

Related Questions