Ambiguity with implicit conversions involving class-type conversions

Hi there,

I have a problem understanding how ambiguity is resolved or when it is reported in implicit (i.e. compiler deduced) conversions that involve class-type conversions. I am aware of few rules involved in implicit conversions but some cases I cannot explain. I am using Microsoft's C++ compiler in VS 2013.

As you know if a function parameter and the corresponding argument from a function call do not match the compiler will try to do an implicit conversion. If either the parameter or the argument is a built-in type and the other is a class-type then the implicit conversion sequence may include a function composition of a class-type conversion and a built-in conversion. Let's consider the following example:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
using namespace std;

class MyInt
{
public:
	operator int()		{ cout << "conversion from MyInt to int" << endl; return val;  }
	operator double()	{ cout << "conversion from MyInt to double" << endl; return val; }
private:
	std::size_t val;
};

void compute(int x) { cout << "inside compute(int)" << endl; }

void main()
{
	MyInt obj;
	compute(obj);
}



This example illustrates having two class-type conversion functions. Considering the declarations the situation is the following:

SmallInt -> int -> int
SmallInt -> double -> int
NON-AMBIGUITY -> first used

The compiler successfully compiles the program. From the program's output we see that the first conversion function is used. It is important to understand that in this case both conversion functions can be used, but in the first case only one class-type conversion function is used (SmallInt -> int) and in the second case both a class-type conversion function (SmallInt -> double) and a built-in conversion (double -> int) are used. Thus the compiler resolves the ambiguity by choosing the first conversion. The first rule is thus that a conversion involving a class-type conversion function is better than another one involving both a class-type conversion function and a built-in conversion.

If we change the declaration(s) in the program to have this situation:

SmallInt -> int -> long int
SmallInt -> double -> long int
AMBIGUITY

the program does not compile. In this case both conversion sequences contain both a class-type and a standard (built-in) conversion which the compiler considers equally good thus it reports ambiguity.

The same is the case in this:

SmallInt -> int -> long double
SmallInt -> double -> long double
AMBIGUITY


What puzzles me are the following cases:

1)
SmallInt -> long int -> int
SmallInt -> double -> int
NON-AMBIGUITY -> first used
- In both cases we have a class-type and a standard conversion!?! Why is the first better?

2)
SmallInt -> unsigned long int -> int
SmallInt -> double -> int
AMBIGUITY
- If the case 1 (long) is unambiguous why is this one (unsigned long) ambiguous?

3)
SmallInt -> short int -> int
SmallInt -> double -> int
NON-AMBIGUITY -> first used
- Is this maybe because the rank of the built-in conversion in the first case (short int -> int) - standard promotion - is better than the rank of the built-in conversion in the second case (double -> int)? If this is true then I am puzzled that the rank of built-in conversions is considered at all since in this case we have two DIFFERENT class-type conversions. I want to remind you that in a related but different issue - function overload resolution - there is a rule which says: If two functions in the overload set can be matched using THE SAME class-type conversion function, then the rank of the standard conversion that follows or precedes the class-type conversion is used to determine which function has the better match. Otherwise, if DIFFERENT class-type conversion operations could be used, then the conversions are considered equally good matches, regardless of the rank of any standard conversions that might or might not be required.

4)
SmallInt -> short int -> int
SmallInt -> signed char -> int
AMBIGUITY


Can anyone give me an explanation for this? I would very much appreciate a reference to a paragraph(s) in the ISO/IEC C++ standard.

best regards

Last edited on
Note that conversion function selection in initialization of function argument is governed by 8.5 and not 13.3.3.2/3. You should consider 13.3.1.5 (My notes in square brackets)
The conversion functions [All of them] of S and its base classes are considered. Those non-explicit conversion functions that are not hidden within S and yield type T or a type that can be converted to type T via a standard conversion sequence (13.3.3.1.1) are candidate functions
Then it uses overload resolution to select best conversion by 13.3.3
the context is an initialization by user-defined conversion (see 8.5, 13.3.1.5, and 13.3.1.6) and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence from the return type of F2 to the destination type.
All conversion functions which can be used to convert to destination type are selected as candidates and then compiler compares standard conversions from return types of those functions to destination type.
So you can drop SmallInt→foo part of conversion when ranking conversions.

(1) It should be an ambiguity. Both GCC and Clang report that. Check with VS2015.
(2) Everything is okay, clear ambiguity.
(3) Promotion is higher rank than conversion (13.3.3.1.1) http://puu.sh/jA6vw/0ff9c953c6.png
(4) Both are promotions, same rank, ambiguity.
Last edited on
Topic archived. No new replies allowed.