Re: Compilation failure involving template operator
Edward Diener wrote:
The code below surprisingly for me fails compilation on Comeau C++ and
VC++ 9:
----------------------------------------------------------
struct XTestChar
{
operator char() const { return c; }
char c;
};
template <class T> struct YTestTemplate { };
template <class T>
YTestTemplate<T> &
operator *= (YTestTemplate<T> & first,T second)
{
return(first);
}
XTestChar xtest;
YTestTemplate<char> ytest;
void AFunction()
{
ytest *= xtest;
}
------------------------------------------------------------
Comeau C++ says:
"ComeauTest.c", line 21: error: no operator "*=" matches these operands
operand types are: YTestTemplate<char> *= XTestChar
ytest *= xtest;
^
1 error detected in the compilation of "ComeauTest.c".
Visual C++ says:
error C2782: 'YTestTemplate<T> &operator *=(YTestTemplate<T> &,T)' :
template parameter 'T' is ambiguous
see declaration of 'operator *='
could be 'XTestChar'
or 'char'
error C2676: binary '*=' : 'YTestTemplate<T>' does not define this
operator or a conversion to a type acceptable to the predefined operator
with
[
T=char
]
I would have thought that the C++ compiler would always deduce T in the
operator*= to be 'char', from the fact that 'ytest' is clearly
'YTestTemplate<char>' and then use XTestChar's char conversion operator
to pass a 'char' to the operator *= function second parameter. Why is
this not allowed ? Are templated operators not allowed to do conversions
when a type is deduced ?
There are only a few "conversions" (difference between arguments and
parameters during deduction) for deduced types that are allowed (see
details
at 14.8.2.1/3):
- An argument that is a derived class of a parameter-type "T<A1, ..., An>"
can be converted to that type (same for pointers or when the parameter is a
reference)
- The parameter-type can be more const-qualified than the argument (looking
through one reference, pointer or pointer-to-member declarator if needed)
Otherwise, the deduction process aims for an exact match of argument and
parameter types, thus no conversions are allowed. You can fix it by making
the second parameter have a non-deduced type
template <class T>
YTestTemplate<T> &
operator *= (YTestTemplate<T> & first, typename identity<T>::type second)
{
return(first);
}
Argument deduction conceptually preceedes overload resolution, and
disregards implicit conversions that are possible mostly.
If I have, in place of my template a normal class and a non-template
operator using that class:
struct YTestClass { };
YTestClass &
operator *= (YTestClass & first,char second)
{
return(first);
}
then
XTestChar xtest;
YTestClass ytestc;
void AFunction()
{
ytestc *= xtest;
}
compiles with no error.
Correct - no template argument deduction takes place.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]