Operator conversion

Hi :)

If I have class String and I use operator conversion to 'print' an object with cout,why do i get no warning ? Isn't that ambiguous :


1
2
3
4
5
6
7
8
9
10
11
12
String::operator string(){
	return "str";
}

String::operator int(){
	return 0;
}

//...

String str;
cout<<str;


It prints "0" . Why not "str" ? Has the int more priority ?
The same with int and char* ...
anyone ?
This is a case of Argument-Dependent-Lookup (ADL). When looking for a potential match for a function call, the compiler first checks the namespace where function's arguments are declared. The definition of the stream operator in this case is:
 
std::ostream& operator(std::ostream& os, /*some value here*/);


Since ostream is defined in the std namespace, the compiler first checks std, and finds the following defined for ostream: (notice that std::string is not here)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ostream& operator<< (bool val);
ostream& operator<< (short val);
ostream& operator<< (unsigned short val);
ostream& operator<< (int val);
ostream& operator<< (unsigned int val);
ostream& operator<< (long val);
ostream& operator<< (unsigned long val);
ostream& operator<< (float val);
ostream& operator<< (double val);
ostream& operator<< (long double val);
ostream& operator<< (void* val);
ostream& operator<< (streambuf* sb );
ostream& operator<< (ostream& (*pf)(ostream&));
ostream& operator<< (ios& (*pf)(ios&));
ostream& operator<< (ios_base& (*pf)(ios_base&));


The compiler checks each name for a match (each of these match the function name) and, if no exact match is found, it tries to find a conversion. Because operator int() is defined, the compiler is able to make a conversion and finishes its search, and does not find your other conversion operator.

Have you tried commenting out operator int() and trying to compile?

As an aside, the common way to implement printing of a user-defined type, write your own << operator for that class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

class String {
    char* m_String;
    // whatever private implementation ....
    public:
 
    const char* c_str() const
    {
        return m_String
    }
    
};

std::ostream& operator<<(std::ostream& os, const String& str)
{
    os << str.c_str();
    return os;
}


operator<< for std::string is also present in the std namespace (assuming <string> was included, which it must have been for the OP code to compile in the first place), The issue here is a little deeper: that operator is a function template, and in order for a function template to become a function, template argument deduction has to take place.

Template argument deduction does not take into account any conversions, so operator<< for std::string is not even considered a candidate for a String argument.

If you manually instantiate the correct template, you will get the string operator called:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <string>
using namespace std;
struct String {
        operator string() { return "str"; }
        operator int() { return 0; }
};

int main()
{
    String s;
    std::operator<< <char, std::char_traits<char>, std::allocator<char> > (std::cout, s);
}


But really, give String its own operator<<, that's the expected way to do it.
Last edited on
Thank you,I understood.
I learn from a book,and there is an example with this type of conversion,so I wanted to understand how it works. I use the operator<< usually.
I said in the last sentence that it happens likewise with int and char* operators.
I cant see char* on the ostream&<< list,but I can print a char* with cout,so this means char* must be on the list.
operator<< for char* is a nonmember operator: http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt2
Topic archived. No new replies allowed.