A question about templates and best viable functions

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

A question about templates and best viable functions

Samuele Panzeri
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);
}

Compiling the previous code result in an error with both GCC and Clang (latest version from code and 3.5 in Archlinux)

test.cpp:51:2: error: call to 'func' is ambiguous
        func(x);
        ^~~~
test.cpp:45:6: note: candidate function
void func(bool) {}
     ^
test.cpp:46:6: note: candidate function
void func(int*) {}
     ^
1 error generated.

The same error can be triggered with a template <class T> operator T* () and using function template argument deduction.

MSC, instead, select func(int*) in all versions from VS2010 to VS2013 CTP 3.

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

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.

Far from being a language expert, I wonder if I'm misreading the standard (or missing something) or if indeed this a bug in clang.

Thanks in advance for the answer,
Samuele


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: A question about templates and best viable functions

Sebastian Redl

On 09 Sep 2014, at 17:24, Samuele Panzeri <[hidden email]> 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
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: A question about templates and best viable functions

Samuele Panzeri
That makes more sense now.
Thank you very much for the answer

On 9 September 2014 17:16, Sebastian Redl <[hidden email]> wrote:

On 09 Sep 2014, at 17:24, Samuele Panzeri <[hidden email]> 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


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: A question about templates and best viable functions

Richard Smith
In reply to this post by Sebastian Redl
On Tue, Sep 9, 2014 at 9:16 AM, Sebastian Redl <[hidden email]> wrote:

On 09 Sep 2014, at 17:24, Samuele Panzeri <[hidden email]> 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);
}

This gives a rather different problem. In the original question, we had

MyStruct -> float* -> bool -> void func(bool)
MyStruct -> T* (T = int) -> void func(int*)

(Note that we can't use the template for the bool overload of func, because we cannot deduce T.) In your version, we have an ambiguous conversion sequence for MyStruct and a user-defined conversion sequence for func(int*).

In the original version, the reason for ambiguity is that user-defined conversion sequences with different conversion functions are incomparable. (See 13.3.3.2/3.2.)
 
>
> 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
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: A question about templates and best viable functions

Sebastian Redl

On 15 Sep 2014, at 3:59, Richard Smith <[hidden email]> wrote:

This gives a rather different problem. In the original question, we had

MyStruct -> float* -> bool -> void func(bool)
MyStruct -> T* (T = int) -> void func(int*)

(Note that we can't use the template for the bool overload of func, because we cannot deduce T.) In your version, we have an ambiguous conversion sequence for MyStruct and a user-defined conversion sequence for func(int*).

The struct is the template, not the conversion operator. And once the struct template is instantiated, there is no difference to a non-template struct.

Sebastian

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: A question about templates and best viable functions

Richard Smith
On Mon, Sep 15, 2014 at 3:42 AM, Sebastian Redl <[hidden email]> wrote:

On 15 Sep 2014, at 3:59, Richard Smith <[hidden email]> wrote:

This gives a rather different problem. In the original question, we had

MyStruct -> float* -> bool -> void func(bool)
MyStruct -> T* (T = int) -> void func(int*)

(Note that we can't use the template for the bool overload of func, because we cannot deduce T.) In your version, we have an ambiguous conversion sequence for MyStruct and a user-defined conversion sequence for func(int*).

The struct is the template, not the conversion operator. And once the struct template is instantiated, there is no difference to a non-template struct.

Sorry, right you are =)

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev