Re: Casting and inheritance, oh my.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]


On 5 April 2012 01:16, Sam Varshavchik wrote:
> If I feed the following to gcc 4.6.3:
>
> #include <sstream>
>
> class Y : public std::ostringstream {
>
> public:
>   using std::ostringstream::operator<<;
> };
>
> Y y;
>
> template<typename x> void cast(const x &z)
> {
>  (std::ostringstream &)y << z;
> }
>
> template<typename x> void inherit(const x &z)
> {
>  y << z;
> }
>
> int int_type;
> char char_array[10];
>
> I get the following results:

In all cases the candidate functions are the overloaded
ostream::operator<<(T) member functions and the non-member
operator<<(ostream&, T) functions.

> cast(int_type);      // This compiles

The best viable function selected by overload resolution is the member
ostream::operator<<(int), which is found in the ostringstream's
ostream base class.

> inherit(int_type);   // This compiles

The best function is the member Y::operator<<(int), which is declared
in Y by the using declaration.

> cast(char_array);    // This compiles

Welcome to Clause 13  ;-)

The best function is the non-member operator<<(ostream&, const char*)
which requires an implicit conversion from ostringstream& to ostream&
for the first argument and array-to-pointer conversion for the second
argument.

> inherit(char_array); // Failure, gcc complains about an ambiguous overload.

Of all the overloads only two are viable, i.e. it has the right number
of arguments (they all do) and there is an implicit conversion
sequence for all the function arguments that allows the function to be
called.

The member Y::operator<<(const void*) declared by the using
declaration requires no conversion for the first argument (the
implicit *this argument) and array-to-pointer conversion then const
char* to const void* pointer conversion.

The non-member operator<<(ostream&, const char*) requires two
conversions, from Y& to ostream& and array-to-pointer conversion.

Overload resolution tries to order the overloads based on the
conversion sequences to find the best viable function. The implicit
conversion sequences for the member function (M) are:

ICS1(M): Y& -> Y&
and
ICS2(M): const char[10] -> const char* -> const void*

The implicit conversion sequences for the non-member function (N) are:

ICS1(N) Y& -> ostream&
ICS2(N) const char[10] -> const char*

ICS1(M) is netter than ICS1(N)
but
ICS2(N) is better than ICS2(M)

The rules in [over.match.best] say the functions are ambiguous,
because there is no function for which all its conversion sequences
are no worse than the other function.

Note that in GCC's output those two functions don't give a reason why
they can't be called (unlike e.g. ostream::operator<<(int) which says
"no known conversion for argument 1 from ‘const char [10]’ to ‘int’").
 That's because they are viable, but neither is a better match than
the other, so they're ambiguous.



[Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

Add to Google