Topic: Template parameter ambiguity
Author: Ralf Stoffels <stoffels@faho.rwth-aachen.de>
Date: 1997/05/15 Raw View
> template <class X, class Y> struct promote;
> template <> struct promote<int, int> { typedef int type; }
> template <> struct promote<int, long> { typedef long type; }
> template <> struct promote<int, double> { typedef double type; }
> /* ... */
>
> template <class T1, class T2, class T3 = promote<T1,T2>::type>
> const T3 min (const T1 &x, const T2 &y)
> { return T3(x) < T3(y) ? T3(x) : T3(y); }
Why is this promote struct not part of the standard ?
If e.g. complex and valarray would be defined like this, it would
be possible to add a complex<float> and an int or add a
valarray<double> and a valarray<float>.
Ralf Stoffels
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: bparker@gil.com.au (Brian Parker)
Date: 1997/04/23 Raw View
Stephen.Clamage@Eng.Sun.COM (Steve Clamage) wrote:
>In article 2q5@xanadu.io.com, jamshid@io.com (Jamshid Afshar) writes:
>>...
>> I thought Standard C++ was going
>>to relax ARM restrictions that template function arguments are an
>>exact match, but according to 14.8.3 "Overload resolution", it does not.
>The ARM required *exact* match on template arguments, and that rule
>has been relaxed. For example, derived-to-base conversion is now
>allowed. (Many compilers allowed that conversion even when it was
>technically disallowed.) Standard promotions and conversions are not
>allowed, however, since they cause too many problems and ambiguities.
I too have found that the draft's rules are too strict in this area.
I can see how allowing all standard promotions and conversions could
cause complications, but what about user-defined conversions? I can't
see how allowing a user-defined conversion when deducing a parameter
of the form class-template-name<arguments> would cause any more
problems than the derived-to-base conversion already allowed by the
CD2.
I have struck this problem with an complex<double> array class that
returns a proxy to differentiate lvalue and rvalue usage (a conversion
operator is called when an rvalue is required). The problem is that
many of the complex functions are template functions that take a
complex<T> and the conversion operator of the proxy isn't called when
doing template argument deduction, which consequently fails.
The compiler could easily match the available user-defined conversions
against complex<T> to find a match.
I was hoping that 14.8.2 [temp.deduct] paragraph 10
"Conversions will be performed on a function argument that
corresponds with a function parameter that contains only non-deducible
parameters..."
would allow user-defined conversions to be called in this case, but
now I am not so sure. (Just what does that paragraph mean?)
BTW is anyone aware of a work-around for this problem or have I missed
something here? Using a proxy class is an important idiom that appears
to be rendered effectively useless for templated types by the current
CD2 rules.
Thanks ,
Brian Parker (bparker@gil.com.au)
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: dHarrison@worldnet.att.net (Doug Harrison)
Date: 1997/04/23 Raw View
On 23 Apr 97 01:53:52 GMT, bparker@gil.com.au (Brian Parker) wrote:
>I was hoping that 14.8.2 [temp.deduct] paragraph 10
> "Conversions will be performed on a function argument that
>corresponds with a function parameter that contains only non-deducible
>parameters..."
>would allow user-defined conversions to be called in this case, but
>now I am not so sure. (Just what does that paragraph mean?)
>
>BTW is anyone aware of a work-around for this problem or have I missed
>something here? Using a proxy class is an important idiom that appears
>to be rendered effectively useless for templated types by the current
>CD2 rules.
Just to let you know you're not alone, I recently ran across a similar
problem in VC++ 5, using char proxies. When I said "cout << c", where
'c' is an object of a char proxy class that provides operator char(),
it printed "65". Saying "cout << char(c)" resulted in the expected
'A'. I believe this should have worked anyway, because the Dec-96 DWP
requires specializations for plain chars, as well as signed and
unsigned chars, which did happen to work fine. VC5 lacks the
plain-char specializations, but note it applied the proxy's operator
char() in order to select the int inserter. What I find odd is that in
considering:
template<class _E, class _Tr> inline
basic_ostream<_E, _Tr>& __cdecl operator<<(
basic_ostream<_E, _Tr>& _O, _E _C)
for:
cout << c;
the template parameters _E and _Tr are fixed by the cout object, so
why doesn't this become, in effect:
ostream& operator<<(ostream&,char);
and why is this an inferior match to basic_ostream::operator<<(int)?
--
Doug Harrison
dHarrison@worldnet.att.net
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: "A. Peter Blicher" <blicher@research.nj.nec.com>
Date: 1997/04/25 Raw View
Steve Clamage wrote:
>
> In article 2q5@xanadu.io.com, jamshid@io.com (Jamshid Afshar) writes:
> >In article <5j0rvs$7ki@xanadu.io.com>, Jamshid Afshar <jamshid@io.com> wrote:
> >>I just want to make sure the following error is a bug in VC++ 5.0. It
> >>gives an error for the second min() call.
> >>
> >> template<class T>
> >> const T& min( const T& x, const T& y)
> >> { return (x<y) ? x : y; }
> >>
> >> int main() {
> >> long q=0, r=0;
> >> min(q,r);
> >> min(q-1,r); // VC++ 5 says T is ambiguous (could be long or int)
> >> return 0;
> >> }
> >
> >I've received e-mail that the above code is legal and the compiler
> >error is a VC++ 5.0 bug. The type of the expression "q-1" is a long,
> >so the call should not be ambiguous.
>
> That is correct.
>
> >I did discover another common problem while recompiling code to use
> >min() and max() templates instead of macros. Unfortunately this one
> >does not seem to be a compiler bug.
> >
> > long l;
> > min( l, 0 ); // okay if min() is a macro, error if it's a template
It seems to me that the real root of this problem is that templates
implement a language for creating compile-time constructs, but not all
the power available to the compiler at compile time is available to the
template writer. In this case, the problem is that there is no access
to the compiler function which promotes an integer type. If there were
such a compile time function, one could write (modulo some syntax):
template<class T1, class T2, class T3 = promote(T1, T2)>
const T3 min(const T1& x, const T2& y)
{ return (T3)x < (T3)y ? (T3)x : (T3)y; }
where promote(long, int) is a compile time function call that returns
'long'.
Unfortunately, what has imho happened in c++ is that rather than use
explicit invocation of compile time functions, as is done e.g. in common
lisp macros, these functions must be invoked implicitly with syntactic
constructs. This has led down the road to large increases in hairiness
to gain small increases in power.
--peter
--
A. Peter Blicher NEC Research Institute
609-951-2716 4 Independence Way
609-951-2488 fax Princeton, NJ 08540-6634 USA
blicher@research.nj.nec.com
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Lassi Tuura <lat@hpatl20.cern.ch>
Date: 1997/04/28 Raw View
"A. Peter Blicher" <blicher@research.nj.nec.com> writes:
> In this case, the problem is that there is no access
> to the compiler function which promotes an integer type. If there were
> such a compile time function, one could write (modulo some syntax):
>
> template<class T1, class T2, class T3 = promote(T1, T2)>
> const T3 min(const T1& x, const T2& y)
> { return (T3)x < (T3)y ? (T3)x : (T3)y; }
>
> where promote(long, int) is a compile time function call that returns
> 'long'.
This is available, although you'd have to code the promotion rules
yourself (not that difficult, tho'). Try something like this:
template <class X, class Y> struct promote;
template <> struct promote<int, int> { typedef int type; }
template <> struct promote<int, long> { typedef long type; }
template <> struct promote<int, double> { typedef double type; }
/* ... */
template <class T1, class T2, class T3 = promote<T1,T2>::type>
const T3 min (const T1 &x, const T2 &y)
{ return T3(x) < T3(y) ? T3(x) : T3(y); }
As you can notice, this is easily extended for user-defined types. An
attempt to employ unknown types will result in compile time error, as
the class `promote' is undefined -- effectively requiring
specialisation for all used combinations.
Cheers,
//lat
--
Lassi.Tuura@cern.ch There's no sunrise without a night
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Stephen.Clamage@Eng.Sun.COM (Steve Clamage)
Date: 1997/04/17 Raw View
In article 2q5@xanadu.io.com, jamshid@io.com (Jamshid Afshar) writes:
>In article <5j0rvs$7ki@xanadu.io.com>, Jamshid Afshar <jamshid@io.com> wrote:
>>I just want to make sure the following error is a bug in VC++ 5.0. It
>>gives an error for the second min() call.
>>
>> template<class T>
>> const T& min( const T& x, const T& y)
>> { return (x<y) ? x : y; }
>>
>> int main() {
>> long q=0, r=0;
>> min(q,r);
>> min(q-1,r); // VC++ 5 says T is ambiguous (could be long or int)
>> return 0;
>> }
>
>I've received e-mail that the above code is legal and the compiler
>error is a VC++ 5.0 bug. The type of the expression "q-1" is a long,
>so the call should not be ambiguous.
That is correct.
>I did discover another common problem while recompiling code to use
>min() and max() templates instead of macros. Unfortunately this one
>does not seem to be a compiler bug.
>
> long l;
> min( l, 0 ); // okay if min() is a macro, error if it's a template
>
>Ugh, appending "L" to all literals or casting when the arguments are
>not the exact same type is a pain. I thought Standard C++ was going
>to relax ARM restrictions that template function arguments are an
>exact match, but according to 14.8.3 "Overload resolution", it does not.
The ARM required *exact* match on template arguments, and that rule
has been relaxed. For example, derived-to-base conversion is now
allowed. (Many compilers allowed that conversion even when it was
technically disallowed.) Standard promotions and conversions are not
allowed, however, since they cause too many problems and ambiguities.
The problem you cite with the "min" template is classic, and I
have several suggestions. I'll use "min" as an example, but
let's also keep in mind the case where the function involved is
more complicated and is not going to be an inline function.
According to the draft standard, you can force a particular
instantiation of a function template by mentioning the type
explicitly at the point of the call:
min<long>(l, 0);
This code requires instantiation of the "min" template on type
long, after which normal argument conversion rules are used
to call the instantiated function. (Not many compilers support
this notation yet.)
Advantages of this solution: You don't have to write any additional
function declarations or definitions, and you don't generate any
unneeded object code.
Disadvantages: You have to mention a particular type, which is error-
prone, and it isn't necessarily nicer than casting one of the operands.
An early rule for templates said that you could force a particular
instantiation by declaring a non-template function that matched
a valid template version. In this case, you would have declared
long min(long, long);
and if you didn't supply a body, the compiler would instantiate
the template version for you. This rule led to many complications
and ambiguities, and was dropped. A non-template declaration
cannot now force instantiation of a template.
But with old or new template rules you can provide that declaration
if you also provide the function definition somewhere:
long min(long l1, long l2) { return (l1 < l2) ? l1 : l2; }
It causes no ambiguity, because in function overloading, a
non-template function is preferred over a template function that is
otherwise an equally good match.
Advantages of this solution: It requires no explicit mention of
types in the call of the min function.
Disadvantages: You must write duplicate versions of functions, which
in general creates maintenance problems. Adding explicit functions
introduces more opportunities for overload ambiguity unless you
are very careful about which ones to add. You could possibly wind up
with both of
long min(long, long){...} // non-template version
long min<long>(long, long){...} // template instantiation
in the program if the declaration for the non-template version
were not in scope at the point where a template version could
be instantiated. The functions have different names, so you don't
get a conflict, just duplicated object code.
With a compiler that supports partial specialization, you can
avoid the duplicated object code but not the duplicated
source code:
template<> long min<long>(long l1, long l2)
{ return (l1 < l2) ? l1 : l2; }
You don't provide a non-template version at all. Now when you write
min(l, 0);
the partial specialization is preferred over generating a function
from the original template, and the specific function allows
normal argument conversion.
Advantages of the partial specialization: You don't have to mention
types at the point of the call, and you don't get duplicated object
code.
Disadvantages: You have to duplicate the function definition. You must
also be sure to include a declaration of the specialization everywhere
the original template is declared. Otherwise you might wind up with
multiple definitions of "min<long>(long, long)", which is an error.
Adding explicit functions introduces more opportunities for overload
ambiguity unless you are very careful about which ones to add.
I don't see that any one of these options is best for all situations.
In the specific case of "min" and "max", I would be tempted to
create a "minmax.h" header which included non-template inline
versions for all built-in arithmetic types, plus a template
declaration.
---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Matt Austern <austern@isolde.mti.sgi.com>
Date: 1997/04/18 Raw View
Stephen.Clamage@Eng.Sun.COM (Steve Clamage) writes:
> >I did discover another common problem while recompiling code to use
> >min() and max() templates instead of macros. Unfortunately this one
> >does not seem to be a compiler bug.
> >
> > long l;
> > min( l, 0 ); // okay if min() is a macro, error if it's a template
> >
[General discussion of template argument matching deleted]
> In the specific case of "min" and "max", I would be tempted to
> create a "minmax.h" header which included non-template inline
> versions for all built-in arithmetic types, plus a template
> declaration.
Except that that wouldn't really solve the original poster's problem,
would it? Fundamentally, I think that this is not really a template
issue at all; it's an overloading issue.
That is, if you have the declarations
long min(long, long);
int min(int, int);
then the call
min(0l, 1);
will be ambiguous (hence illegal) because neither signature is a best
match for both arguments.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: jamshid@io.com (Jamshid Afshar)
Date: 1997/04/15 Raw View
I just want to make sure the following error is a bug in VC++ 5.0. It
gives an error for the second min() call.
template<class T>
const T& min( const T& x, const T& y)
{ return (x<y) ? x : y; }
int main() {
long q=0, r=0;
min(q,r);
min(q-1,r); // VC++ 5 says T is ambiguous (could be long or int)
return 0;
}
Thanks,
Jamshid Afshar
jamshid@io.com
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: jamshid@io.com (Jamshid Afshar)
Date: 1997/04/16 Raw View
In article <5j0rvs$7ki@xanadu.io.com>, Jamshid Afshar <jamshid@io.com> wrote:
>I just want to make sure the following error is a bug in VC++ 5.0. It
>gives an error for the second min() call.
>
> template<class T>
> const T& min( const T& x, const T& y)
> { return (x<y) ? x : y; }
>
> int main() {
> long q=0, r=0;
> min(q,r);
> min(q-1,r); // VC++ 5 says T is ambiguous (could be long or int)
> return 0;
> }
I've received e-mail that the above code is legal and the compiler
error is a VC++ 5.0 bug. The type of the expression "q-1" is a long,
so the call should not be ambiguous.
I did discover another common problem while recompiling code to use
min() and max() templates instead of macros. Unfortunately this one
does not seem to be a compiler bug.
long l;
min( l, 0 ); // okay if min() is a macro, error if it's a template
Ugh, appending "L" to all literals or casting when the arguments are
not the exact same type is a pain. I thought Standard C++ was going
to relax ARM restrictions that template function arguments are an
exact match, but according to 14.8.3 "Overload resolution", it does
not.
Jamshid Afshar
jamshid@io.com
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: John Lilley <jlilley@empathy.com>
Date: 1997/04/17 Raw View
Jamshid Afshar wrote:
> template<class T>
> const T& min( const T& x, const T& y)
> { return (x<y) ? x : y; }
>
> int main() {
> long q=0, r=0;
> min(q,r);
> min(q-1,r); // VC++ 5 says T is ambiguous
> }
My reading of CD2 sections 4.5 [conv.prom] 2.13 [lex.literal] and 5/9
[expr/9] requires that (a) the literal '1' be of type 'int', and (b) the
expression "q-1" be of type "long". However, VC++ 4.2 (and I assume 5.0
judging from the error message) incorrectly determines athe type of the
expression to be "int", as you can test by the following program:
#include <iostream>
void f(int) { cout << "f(int)" << endl; }
void f(long) { cout << "f(long)" << endl; }
int main() {
long q=0;
f(q);
f(q-1);
return 0;
}
Which outputs:
f(long);
f(int);
So much for my hopes that VC++ 5.0 would be a big improvement. I was
hoping that they would nail template partial specialization, but if they
can't even get types of expressions right, it's kind of pointless. What
crap! Guess I won't install the upgrade quite yet.
john lilley
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: comeau@panix.com (Greg Comeau)
Date: 1997/04/17 Raw View
In article <3355017E.347C@empathy.com> John Lilley <jlilley@empathy.com> writes:
>
>Jamshid Afshar wrote:
>> template<class T>
>> const T& min( const T& x, const T& y)
>> { return (x<y) ? x : y; }
>>
>> int main() {
>> long q=0, r=0;
>> min(q,r);
>> min(q-1,r); // VC++ 5 says T is ambiguous
>> }
>
>My reading of CD2 sections 4.5 [conv.prom] 2.13 [lex.literal] and 5/9
>[expr/9] requires that (a) the literal '1' be of type 'int',
It does? You mean so that q-1 will remain a long I suppose?
> and (b) the expression "q-1" be of type "long"
How is it otherwise?
Let's see. Ok, the real deal here is from what it discussed in 5/9:
A long - int is a long.
>However, VC++ 4.2 (and I assume 5.0
>judging from the error message) incorrectly determines athe type of the
>expression to be "int", as you can test by the following program:
>
>#include <iostream>
>void f(int) { cout << "f(int)" << endl; }
>void f(long) { cout << "f(long)" << endl; }
>int main() {
> long q=0;
> f(q);
> f(q-1);
> return 0;
>}
>
>Which outputs:
>f(long);
>f(int);
>
Ouch! This can be a real gotcha on such a fundamental issue.
- Greg
--
Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418-3214
Producers of Comeau C++ 4.0 front-end pre-release
****WEB: http://www.comeaucomputing.com / Voice:718-945-0009 / Fax:718-441-2310
Here:comeau@comeaucomputing.com / BIX:comeau or comeau@bix.com / CIS:72331,3421
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]