Hi,

I think I remember that template member functions do not trigger
user-defined conversions.
The code below in fact does not compile. instead if I remove the cast
operator from C and let C derive from A, it succeeds.
Is the explanation correct?

TIA,
MH



template <typename T>
struct A {};

struct B
{
template <typename T>
bool operator==(A<T>) const
{
return true;
}
};

struct C // : public A<int>
{
operator A<int>() const
{
return A<int>();
}
};

int main()
{
C c;
B b;
return b == c;
}

Re: a language question about conversion operators by Victor

Victor
Fri Oct 26 08:50:38 PDT 2007

Mycroft Holmes wrote:
> I think I remember that template member functions do not trigger
> user-defined conversions.

You mean, during template argument deduction user-defined conversions
are not considered? Yes, that's true. If that's not what you meant,
I don't have an answer.

> The code below in fact does not compile. instead if I remove the cast
> operator from C and let C derive from A, it succeeds.
> Is the explanation correct?

Uh... Not sure what you mean.

>
> TIA,
> MH
>
>
>
> template <typename T>
> struct A {};
>
> struct B
> {
> template <typename T>
> bool operator==(A<T>) const
> {
> return true;
> }
> };
>
> struct C // : public A<int>
> {
> operator A<int>() const
> {
> return A<int>();
> }
> };
>
> int main()
> {
> C c;
> B b;
> return b == c;
> }

I believe the inheritance establishes a much stronger "is-a" relationship
between 'C' and 'A<int>' than the presence of the conversion function.
And I guess it's the reason why the Standard says that the argument from
which the template arg is deduced can be the derived class of the specified
parameter.

In order to deduce the 'T' to instantiate the 'B::operator==' function,
the compiler looks at the argument. It's a C. Is it one of instantiations
of 'A'? No. Is its base classes one of instantiations of 'A'? No. Can't
do it.

Now, if 'C' derives from 'A<int>', process goes: [same...] Is its base
classes one of instantiations of 'A'? Yes! Which one? 'A<int>'. Now
we can match 'T' to 'int' to arrive to the identical template. The task
accomplished, 'T' is deduced as 'int'.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask



Re: a language question about conversion operators by Feng

Feng
Fri Oct 26 22:03:48 PDT 2007

Only to overload a operater that exists is allowed.

How to overload "A<int>"??

Thanks.





"Victor Bazarov" <v.Abazarov@comAcast.net> дÈëÏûÏ¢ÐÂÎÅ:fft2cf$t37$1@news.datemas.de...
> Mycroft Holmes wrote:
>> I think I remember that template member functions do not trigger
>> user-defined conversions.
>
> You mean, during template argument deduction user-defined conversions
> are not considered? Yes, that's true. If that's not what you meant,
> I don't have an answer.
>
>> The code below in fact does not compile. instead if I remove the cast
>> operator from C and let C derive from A, it succeeds.
>> Is the explanation correct?
>
> Uh... Not sure what you mean.
>
>>
>> TIA,
>> MH
>>
>>
>>
>> template <typename T>
>> struct A {};
>>
>> struct B
>> {
>> template <typename T>
>> bool operator==(A<T>) const
>> {
>> return true;
>> }
>> };
>>
>> struct C // : public A<int>
>> {
>> operator A<int>() const
>> {
>> return A<int>();
>> }
>> };
>>
>> int main()
>> {
>> C c;
>> B b;
>> return b == c;
>> }
>
> I believe the inheritance establishes a much stronger "is-a" relationship
> between 'C' and 'A<int>' than the presence of the conversion function.
> And I guess it's the reason why the Standard says that the argument from
> which the template arg is deduced can be the derived class of the
> specified
> parameter.
>
> In order to deduce the 'T' to instantiate the 'B::operator==' function,
> the compiler looks at the argument. It's a C. Is it one of
> instantiations
> of 'A'? No. Is its base classes one of instantiations of 'A'? No.
> Can't
> do it.
>
> Now, if 'C' derives from 'A<int>', process goes: [same...] Is its base
> classes one of instantiations of 'A'? Yes! Which one? 'A<int>'. Now
> we can match 'T' to 'int' to arrive to the identical template. The task
> accomplished, 'T' is deduced as 'int'.
>
> V
> --
> Please remove capital 'A's when replying by e-mail
> I do not respond to top-posted replies, please don't ask
>



Re: a language question about conversion operators by Mycroft

Mycroft
Mon Oct 29 03:00:05 PDT 2007

>> I think I remember that template member functions do not trigger
>> user-defined conversions.
>
> You mean, during template argument deduction user-defined conversions
> are not considered?

right, that's what I should have written.
thanks for translating


> In order to deduce the 'T' to instantiate the 'B::operator==' function,
> the compiler looks at the argument. It's a C. Is it one of
> instantiations
> of 'A'? No. Is its base classes one of instantiations of 'A'? No.
> Can't
> do it.


obviously, it would be technically possible for the compiler to add another
step that says: can C be convert to A<T1> for some fixed T1?
but if it does not,


In the real code, we have a template that reproduces std::pair, but
first_type and second_type may be references.
since we'd like interoperability with std::pair, we implemented a
user-defined conversion operator to std::pair<V1, V2> where V1 is
remove_reference<first_type>, etc.
this worked fine until someone tried on a member function that takes
pair<T1,T2> for any T1,T2.

at the moment we are considering derivation from (say) std::pair<X1, X2>
where X1 is first_type or some appropriate reference wrapper.





Re: a language question about conversion operators by Mycroft

Mycroft
Mon Oct 29 03:06:56 PDT 2007

>
>> In order to deduce the 'T' to instantiate the 'B::operator==' function,
>> the compiler looks at the argument. It's a C. Is it one of
>> instantiations
>> of 'A'? No. Is its base classes one of instantiations of 'A'? No.
>> Can't
>> do it.
>
>
> obviously, it would be technically possible for the compiler to add
> another step that says: can C be convert to A<T1> for some fixed T1?
> but if it does not,
>

sorry, I sent the message before finishing the sentence.

obviously, it would be technically possible for the compiler to add another
step that says: can C be convert to A<T1> for some fixed non-ambiguous T1?
if it can, then T1 is the type you require, otherwise the conversion is
impossible or ambiguous.



Re: a language question about conversion operators by Igor

Igor
Mon Oct 29 05:45:30 PDT 2007

"Mycroft Holmes" <m.holmes@nospam.it> wrote in message
news:OyRM3NhGIHA.1548@TK2MSFTNGP05.phx.gbl
>>> In order to deduce the 'T' to instantiate the 'B::operator=='
>>> function, the compiler looks at the argument. It's a C. Is it one
>>> of instantiations
>>> of 'A'? No. Is its base classes one of instantiations of 'A'? No.
>>> Can't
>>> do it.
>>
>>
>> obviously, it would be technically possible for the compiler to add
>> another step that says: can C be convert to A<T1> for some fixed T1?
>> but if it does not,
>>
>
> sorry, I sent the message before finishing the sentence.
>
> obviously, it would be technically possible for the compiler to add
> another step that says: can C be convert to A<T1> for some fixed
> non-ambiguous T1? if it can, then T1 is the type you require,
> otherwise the conversion is impossible or ambiguous.

Conversion operator is not the only means by which C can be converted to
some other class. That class could also have a constructor from C:

template <typename T>
struct A {};

template <typename T>
void f(A<T>);

struct C {};

struct D : A<int> {
D(const C&);
}

C c;
f(c); // f<int>( D(c) ); ?

The constuctor and the conversion operator are pretty much doing the
same thing, only from different ends. Both are considered for implicit
type conversions by the compiler. It can be argued that conversion
constructors are much more common in practice than conversion operators.

But of course, to support such type inference, the compiler would have
to search the whole program for a class that may be constructed from C
and also may be somehow related to A<T> for some T. You get spooky
action at a distance: adding a new class may suddenly change the meaning
of a seemingly unrelated part of the program. You would also have to
#include every class that might have the slightest bearing on the
relationship between C and A<T> everywhere f<T> may be used, or risk ODR
violations (imagine two translation units calling f(c), one of which
includes D.h and the other E.h where class E also has constructor from
C).
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925