c++operator-overloadingimplicit-conversionconversion-operator

Implicit Conversion Operator for Class Objects to Strings


I'm learning more about implicit conversion operators, and I've noticed something strange with implicit user-defined conversions for strings. Found below is the code.

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

class A {
    public:
        A() {
            *value = "YIKERS";
        } 
        operator string&() {
            return *this->value;
        }
        string* value;
};


int main() {
    A abc;
    cout << abc << endl; 
// compile error: invalid operands to binary expression ('std::__1::ostream' (aka
// 'basic_ostream<char>') and 'A')
    return 0;
}

Any ideas as to why I'm getting this compilation error? I'm thinking this could mean that the object isn't being implicitly converted to a string? If so, why not? Is there a way to fix this? The conversion operator works perfectly fine for other data types like int, float, char, etc.


Solution

  • First of all, I think you're not using std::string value as intended. This causes another compile error (at least on gcc 10.2). It seems like you want a string and you're using a pointer to a string. This can be fixed by replace string* value with string value, operator string&() with operator string() and *value = "YIKERS' with value = "YIKERS". For the last one you might also want to check initializer lists.

    Regarding the current compile error:

    The compile error is caused by the code cout << abc trying to use operator<< on an abc which is an object of type A. However, you did not overload this operator. In your example this could be something like

    friend std::ostream &operator<<(std::ostream &output, const A &a ) 
    { 
        output << a.value;
        return output;            
    }
    

    Even if you have a user-defined conversion to std::string you would still get compile time errors. This link explains it better than I think I could Why cannot use cout with user-defined conversion to std::string?

    This is how I understand the explanation from link above:

    string header defines the following overload for operator<< for std::basic_ostream:

    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);
    

    Also, std::string is actually a typedef for std::basic_string<char>.

    However, if the conversion is implicit the following rule kicks in:

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

    So, the compiler cannot deduce the second parameter for the function (e.g. const std::basic_string<CharT, Traits, Allocator>& str) from A. It can, however, deduce it for string so you can explicitly convert abc to string like static_cast<string>(abc) and that would work.