[cfe-dev] A question about templates and best viable functions

Sebastian Redl sebastian.redl at getdesigned.at
Tue Sep 9 09:16:59 PDT 2014


On 09 Sep 2014, at 17:24, Samuele Panzeri <samuele.panzeri at gmail.com> wrote:

> Hi,
> 
> I was experimenting some code and I incurred in an unexpected error.
> I reduce the code to the minimal case:
> 
> template <class T>
> struct MyStruct {
> 	operator float* () { return 0; }
> 	operator T* () { return 0; }
> };
> void func(bool) {}
> void func(int*) {}
> int main() {
> 	MyStruct<int> x;
> 	func(x);
> }

This isn’t minimal. There’s no need for the template; this code yields the same results (in Clang, at least):

struct MyStruct {
	operator float* () { return 0; }
	operator int* () { return 0; }
};
void func(bool) {}
void func(int*) {}
int main() {
	MyStruct x;
	func(x);
}


> 
> Now, I was wondering which one is the expected behaviour according to the standard.
> From 13.3.3 (Best Viable Function):
> 
> — 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

This bullet point doesn’t apply. The context that is ambiguous is the function call func(x), not the decision between the two conversion operators (that’s a separate, nested overloading decision while determining the conversion sequences for each of the two variants of func).

> 
> In this case both the function call require user defined conversion.
> 
> The one using non-template parameter yield to a standard conversion sequence of type boolean conversion (4.12).
> 
> The UDC with a template parameter should resolve in a user defined conversion followed by a standard conversion of identity type (exact match).
> 
> Intuitively I would expect this second conversion to be considered a better match than the latter one and be selected.

I agree that it is intuitive, but let’s look at it more formally.

When the compiler sees func(x), it has to decide between calling func(bool) and func(int*). The argument in either case is of type MyStruct. To decide, it individually finds the conversion sequences for all parameters of all candidates.

func(bool) can be called in two ways: MyStruct->int*->bool and MyStruct->float*->bool. Since neither is better than the other, the conversion is the “ambiguous conversion sequence” (13.3.3.1p10), which "is treated as a user-defined sequence that is indistinguishable from any other user-defined conversion sequence”.

func(int*) can be called in one way: MyStruct->int*. This is a user-defined conversion sequence.

Since the ACS for func(bool) is, by definition, indistinguishable from the UDCS for func(int*), the call is ambiguous. Clang and GCC are correct, MSVC is wrong.

This case is an unfortunate casualty of preventing a more dangerous unintuitive situation, as described in the footnote referenced by my quoted standard paragraph. Making this particular case work again would require that the ambiguous conversion sequence somehow keep its trailing standard conversion sequences around (or at least the best one) for the purpose of comparing it to the trailing standard conversion sequence in other overloads - a significant increase in complexity for overload resolution.

Sebastian



More information about the cfe-dev mailing list