Topic: Color me clueless
Author: smeyers@aristeia.com (Scott Meyers)
Date: 2000/06/29 Raw View
I hate it when code compiles and I think it shouldn't. Consider:
template<typename T1,
typename T2> // this f takes two parameters, which
void f(T1&, const T2&); // may be of different types
template<typename T> // this f takes two paramerers, which
void f(T&, const T&); // must be of basically the same type
int main()
{
std::vector<int> v1, v2;
f(v1, v2); // call f with two args of the same type
}
I expected this call to be ambiguous, because for the first f, the type
parameters T1 and T2 can both be bound to the same type (vector<int> in
this case), while for the second f, the single type parameter can be bound
to the one type needed.
To my astonishment, g++, mwcc, and bcc32 all call the second f, the one
with only a single type argument. Can somebody please explain why the
second f is preferred to the first one?
Thanks,
Scott
---
[ 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 ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: wmm@fastdial.net
Date: 2000/06/30 Raw View
In article <MPG.13c480f277f3d435989709@news.supernews.com>,
smeyers@aristeia.com (Scott Meyers) wrote:
> I hate it when code compiles and I think it shouldn't. Consider:
>
> template<typename T1,
> typename T2> // this f takes two parameters, which
> void f(T1&, const T2&); // may be of different types
>
> template<typename T> // this f takes two paramerers, which
> void f(T&, const T&); // must be of basically the same type
>
> int main()
> {
> std::vector<int> v1, v2;
>
> f(v1, v2); // call f with two args of the same type
> }
>
> I expected this call to be ambiguous, because for the first f, the
type
> parameters T1 and T2 can both be bound to the same type (vector<int>
in
> this case), while for the second f, the single type parameter can be
bound
> to the one type needed.
>
> To my astonishment, g++, mwcc, and bcc32 all call the second f, the
one
> with only a single type argument. Can somebody please explain why the
> second f is preferred to the first one?
Sure. This is what's called "partial ordering" of function
templates (see 14.5.5.2 in the Standard). To paraphrase, if
more than one function template matches a given call, the
ambiguity is resolved in favor of a template that is "more
specialized" than another.
The way you compare function templates for this check is to
create fake types/values for the template parameters of one
function, substitute those into that function's parameter
list, and use the resulting list of types as if they were
the types of arguments to do template argument deduction on
the other function. You do that in both directions for the
pair of functions, and if one direction succeeds and the
other fails, you've established that one function is more
specialized than the other.
Here's how it works for your example. Let's start with the
second of your functions, the one with one template parameter.
We invent a type for its parameter, call it "Q1", and
substitute it into the function's parameter list. The result
is "(Q1&, const Q1&)". Now we take that list and try to do
template argument deduction on the first function template,
using the list as if it had come from the types of the
arguments in a function call. The deduction succeeds, giving
(after reference decay) T1 as Q1 and T2 as Q1.
Now we try the other direction. We invent types for the
template parameters of the first function, say "Z1" for T1 and
"Z2" for T2. When we try to do template argument deduction
using the resulting list, "(Z1&, const Z2&)", on the second
function, however, the deduction fails -- the two function
parameters must have the same base type, and Z1 and Z2 are
distinct types.
Since the deduction from the second to the first function
succeeded but the deduction from the first to the second
failed, we say that the second function template is more
specialized than the first, so the ambiguity in the call is
resolved in favor of the second.
This process is basically analogous to partial specialization
of class templates -- the idea is that you might be able to
make use of certain optimizations or simplifying assumptions
in implementing a function if you know that some particular
relationship holds among the template arguments. In this
case, you'd write the general algorithm in the first function
and provide a special-purpose algorithm in the second that
only works if the two function parameters have the same type.
--
William M. Miller, wmm@fastdial.net
OnDisplay, Inc. (www.ondisplay.com)
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ 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 ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Richard Parkin" <rparkin@msi-eu.com>
Date: 2000/06/30 Raw View
Scott Meyers <smeyers@aristeia.com> wrote in message
news:MPG.13c480f277f3d435989709@news.supernews.com...
> I hate it when code compiles and I think it shouldn't. Consider:
>
> template<typename T1,
> typename T2> // this f takes two parameters, which
> void f(T1&, const T2&); // may be of different types
>
> template<typename T> // this f takes two paramerers, which
> void f(T&, const T&); // must be of basically the same type
>
> int main()
> {
> std::vector<int> v1, v2;
>
> f(v1, v2); // call f with two args of the same type
> }
>
> I expected this call to be ambiguous, because for the first f, the type
> parameters T1 and T2 can both be bound to the same type (vector<int> in
> this case), while for the second f, the single type parameter can be bound
> to the one type needed.
>
> To my astonishment, g++, mwcc, and bcc32 all call the second f, the one
> with only a single type argument. Can somebody please explain why the
> second f is preferred to the first one?
Off the top of my head, isn't this to do with the single version being
<fumbles for right word> 'simpler', 'closest'?
There's some rule I've seen mentioned around here where it chooses the
version that requires fewest template parameters to meet the requirements.
I'm sure someone has a copy of the standard to hand which has the details?
Ric
---
[ 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 ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Pete Becker <petebecker@acm.org>
Date: 2000/06/30 Raw View
Scott Meyers wrote:
>
> I hate it when code compiles and I think it shouldn't. Consider:
>
> template<typename T1,
> typename T2> // this f takes two parameters, which
> void f(T1&, const T2&); // may be of different types
>
> template<typename T> // this f takes two paramerers, which
> void f(T&, const T&); // must be of basically the same type
>
> int main()
> {
> std::vector<int> v1, v2;
>
> f(v1, v2); // call f with two args of the same type
> }
>
> I expected this call to be ambiguous, because for the first f, the type
> parameters T1 and T2 can both be bound to the same type (vector<int> in
> this case), while for the second f, the single type parameter can be bound
> to the one type needed.
>
> To my astonishment, g++, mwcc, and bcc32 all call the second f, the one
> with only a single type argument. Can somebody please explain why the
> second f is preferred to the first one?
>
Clause 14.5.5.2 describes partial ordering of function templates. In
broad strokes, the first one could be applied to all cases where the
second one could be applied, and then some. So the second one is more
specialized, and the rules say that the more specialized one will be
chosen.
It's really just a generalization of:
template<class T> void f(T *);
void f(int *);
int i;
f(&i); // calls f(int*), not f<int>.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
Contibuting Editor, C/C++ Users Journal (http://www.cuj.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 ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 2000/06/30 Raw View
Scott Meyers wrote:
>
> I hate it when code compiles and I think it shouldn't. Consider:
>
> template<typename T1,
> typename T2> // this f takes two parameters, which
> void f(T1&, const T2&); // may be of different types
>
> template<typename T> // this f takes two paramerers, which
> void f(T&, const T&); // must be of basically the same type
>
> int main()
> {
> std::vector<int> v1, v2;
>
> f(v1, v2); // call f with two args of the same type
> }
>
> I expected this call to be ambiguous, because for the first f, the type
> parameters T1 and T2 can both be bound to the same type (vector<int> in
> this case), while for the second f, the single type parameter can be bound
> to the one type needed.
>
> To my astonishment, g++, mwcc, and bcc32 all call the second f, the one
> with only a single type argument. Can somebody please explain why the
> second f is preferred to the first one?
Because it is better according to template function partial ordering.
Basically that means in every case where you can instantiate the
second template, you also can instantiate the first one, but there
are calls possible on the first one which are not possible on the
second one.
Of course, the exact definition is more complex, see
(numbers from CD2, because I don't have a copy of the standard):
CD2 14.5.5.2 [temp.func.order]/1 to 4
(and CD2 13.3.3 [over.match.best]/1 tells that the more
specialized version is a better match).
---
[ 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 ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James Kuyper <kuyper@wizard.net>
Date: 2000/06/30 Raw View
Scott Meyers wrote:
>
> I hate it when code compiles and I think it shouldn't. Consider:
>
> template<typename T1,
> typename T2> // this f takes two parameters, which
> void f(T1&, const T2&); // may be of different types
>
> template<typename T> // this f takes two paramerers, which
> void f(T&, const T&); // must be of basically the same type
>
> int main()
> {
> std::vector<int> v1, v2;
>
> f(v1, v2); // call f with two args of the same type
> }
>
> I expected this call to be ambiguous, because for the first f, the type
> parameters T1 and T2 can both be bound to the same type (vector<int> in
> this case), while for the second f, the single type parameter can be bound
> to the one type needed.
>
> To my astonishment, g++, mwcc, and bcc32 all call the second f, the one
> with only a single type argument. Can somebody please explain why the
> second f is preferred to the first one?
Because the second template requires less work to match the call. Now
I've got to find the exact wording in the standard which says that. ....
Found it! - Section 13.3.3p1: "... F1 is ... a _better_ function than
.... F2 ... if ... F1 and F2 are template functions, and the function
template for F1 is more specialized than the template for F2 according
to the partial ordering rules described in 14.5.5.2 ..."
Section 14.5.5.2 describes a process that I will apply to your case:
For your first template, I provide a unique type for each template
argument, say T1=int and T2=long. Then I try to perform argument
deduction using those types against the second template. That attempt
fails, since the second argument's type has to be the same as the first,
except for a 'const'. Conclusion: per 14.5.5.2p4, the first template is
not at least as specialized as the second.
For the second template, I provide a unique type for each template
argument, say T='double', since there's only one argument. I then try to
perform argument deduction against the first template. That attempt
succeeds by setting both T1 and T2 equal to 'double'. Therefore, the
second template is at least as specialized as the first.
Since the first one is not at least as specialized as the second, and
the second is at least as specialized as the first, applying 14.5.5.2p5,
we conclude that the second template is more specialized than the first.
Therefore, it's favored under partial ordering of templates, and
therefore the call is not ambiguous.
This is a deliberate and useful feature. Your second template could
never be called except with explicit arguments, without the partial
ordering rules. Even with explicit arguments, it would remain ambiguous.
In general the more specialized template will have fewer arguments.
Therefore, a call to the more specialized template with explicit
arguments will look identical to a call to the less specialized
template, with the extra arguments left free for argument deduction. If
there were no rule favoring the more specialized template, such calls
would always be ambiguous.
---
[ 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 ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: herwin@gmu.edu (Harry Erwin)
Date: 2000/06/30 Raw View
Scott Meyers <smeyers@aristeia.com> wrote:
> I hate it when code compiles and I think it shouldn't. Consider:
>
> template<typename T1,
> typename T2> // this f takes two parameters, which
> void f(T1&, const T2&); // may be of different types
>
> template<typename T> // this f takes two paramerers, which
> void f(T&, const T&); // must be of basically the same type
>
> int main()
> {
> std::vector<int> v1, v2;
>
> f(v1, v2); // call f with two args of the same type
> }
>
> I expected this call to be ambiguous, because for the first f, the type
> parameters T1 and T2 can both be bound to the same type (vector<int> in
> this case), while for the second f, the single type parameter can be bound
> to the one type needed.
>
> To my astonishment, g++, mwcc, and bcc32 all call the second f, the one
> with only a single type argument. Can somebody please explain why the
> second f is preferred to the first one?
>
> Thanks,
>
Class template partial specialization. Section 14.5.4 of the standard
discusses this specific case.
--
Harry Erwin, PhD, <mailto:herwin@gmu.edu>,Computational Neuroscientist
(modeling bat behavior), Senior SW Analyst and Security Engineer, and
Adjunct Professor of Computer Science, GMU. Looking--CV available at:
<http://mason.gmu.edu/~herwin/CV.htm>
---
[ 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 ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Vincenzo Vasta" <vvasta@nortelnetworks.com>
Date: 2000/06/30 Raw View
--------------BA753F84A9F222180D4F179D
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
When I've seen your post I was astonished too, so I've tried to compile
the code on my HP compiler and I've got the same result.
It seems that the version with the single parameter is more specialized
than the other, why ? Looking at the standard 14.5.5.2 it says:
a template is more specialized than another, if and only if, it is at least
as specialized as the other template and that template is not at least
as specialized as the first.
Before this, it describes a method to know when a template is at least as
specialized as another and from what I understood the second f is more
specialized than the first because in every place where we use the second
we can use the first, but there are some cases (when the two parameters
are different) where the first can't be substituted from the second. It
makes sense but I'm not really sure of this.
Cheers
Vincenzo
Scott Meyers wrote:
> I hate it when code compiles and I think it shouldn't. Consider:
>
> template<typename T1,
> typename T2> // this f takes two parameters, which
> void f(T1&, const T2&); // may be of different types
>
> template<typename T> // this f takes two paramerers, which
> void f(T&, const T&); // must be of basically the same type
>
> int main()
> {
> std::vector<int> v1, v2;
>
> f(v1, v2); // call f with two args of the same type
> }
>
> I expected this call to be ambiguous, because for the first f, the type
> parameters T1 and T2 can both be bound to the same type (vector<int> in
> this case), while for the second f, the single type parameter can be bound
> to the one type needed.
>
> To my astonishment, g++, mwcc, and bcc32 all call the second f, the one
> with only a single type argument. Can somebody please explain why the
> second f is preferred to the first one?
>
> Thanks,
>
> Scott
>
> ---
> [ 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 ]
> [ --- Please see the FAQ before posting. --- ]
> [ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
--
------------------------------------------------
Vincenzo Vasta
Software Engineer
Preside Integrated Management
Nortel Networks, New Southgate,
London, N11 1HB, UK
Tel: +44 (0)208-945-3676 (ESN-730-3676)
Fax: +44 (0)208-945-2700 (ESN-730-2700)
email: vvasta@nortelnetworks.com
------------------------------------------------
--------------BA753F84A9F222180D4F179D
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
When I've seen your post I was astonished too, so I've tried to compile
<BR>the code on my HP compiler and I've got the same result.
<BR>It seems that the version with the single parameter is more specialized
<BR>than the other, why ? Looking at the standard 14.5.5.2 it says:
<P> a template is more specialized than another, if and only if,
it is at least
<BR> as specialized as the other template and that template is not
at least
<BR> as specialized as the first.
<P>Before this, it describes a method to know when a template is at least
as
<BR>specialized as another and from what I understood the second f is more
<BR>specialized than the first because in every place where we use the
second
<BR>we can use the first, but there are some cases (when the two parameters
<BR>are different) where the first can't be substituted from the second.
It
<BR>makes sense but I'm not really sure of this.
<P> Cheers
<BR> Vincenzo
<BR>
<BR>
<P>Scott Meyers wrote:
<BLOCKQUOTE TYPE=CITE>I hate it when code compiles and I think it shouldn't.
Consider:
<P> template<typename T1,
<BR> typename T2>
// this f takes two parameters, which
<BR> void f(T1&, const T2&); // may
be of different types
<P> template<typename T>
// this f takes two paramerers, which
<BR> void f(T&, const T&);
// must be of basically the same type
<P> int main()
<BR> {
<BR> std::vector<int> v1, v2;
<P> f(v1, v2);
// call f with two args of the same type
<BR> }
<P>I expected this call to be ambiguous, because for the first f, the type
<BR>parameters T1 and T2 can both be bound to the same type (vector<int>
in
<BR>this case), while for the second f, the single type parameter can be
bound
<BR>to the one type needed.
<P>To my astonishment, g++, mwcc, and bcc32 all call the second f, the
one
<BR>with only a single type argument. Can somebody please explain
why the
<BR>second f is preferred to the first one?
<P>Thanks,
<P>Scott
<P>---
<BR>[ comp.std.c++ is moderated. To submit articles, try just posting
with ]
<BR>[ your news-reader. If that fails, use <A HREF="mailto:std-c++@ncar.ucar.edu">mailto:std-c++@ncar.ucar.edu</A>
]
<BR>[
--- Please see the FAQ before posting. ---
]
<BR>[ FAQ: <A HREF="http://reality.sgi.com/austern_mti/std-c++/faq.html">http://reality.sgi.com/austern_mti/std-c++/faq.html</A>
]</BLOCKQUOTE>
<PRE>--
------------------------------------------------
Vincenzo Vasta
Software Engineer
Preside Integrated Management
Nortel Networks, New Southgate,
London, N11 1HB, UK
Tel: +44 (0)208-945-3676 (ESN-730-3676)
Fax: +44 (0)208-945-2700 (ESN-730-2700)
email: vvasta@nortelnetworks.com
------------------------------------------------</PRE>
</HTML>
--------------BA753F84A9F222180D4F179D--
======================================= MODERATOR'S COMMENT:
In general, comp.std.c++ prefers text only (i.e., non HTML) posts.
---
[ 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 ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 2000/06/30 Raw View
smeyers@aristeia.com (Scott Meyers) writes:
> I hate it when code compiles and I think it shouldn't. Consider:
> template<typename T1, typename T2> void f(T1 &, const T2 &);
> template<typename T> void f(T &, const T &);
> int main()
> {
> std::vector<int> v1, v2;
> f(v1, v2);
> }
> I expected this call to be ambiguous
Nope. You forgot partial ordering of function templates, 14.5.5.2.
The template with one parameter is more specialized than the one
with two by the rules of that section.
---
[ 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 ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Alain Miniussi <alainm@cup.hp.com>
Date: 2000/07/02 Raw View
Scott Meyers wrote:
>
> I hate it when code compiles and I think it shouldn't. Consider:
>
> template<typename T1,
> typename T2> // this f takes two parameters, which
> void f(T1&, const T2&); // may be of different types
>
> template<typename T> // this f takes two paramerers, which
> void f(T&, const T&); // must be of basically the same type
>
> int main()
> {
> std::vector<int> v1, v2;
>
> f(v1, v2); // call f with two args of the same type
> }
>
> I expected this call to be ambiguous, because for the first f, the type
> parameters T1 and T2 can both be bound to the same type (vector<int> in
> this case), while for the second f, the single type parameter can be bound
> to the one type needed.
You are right in the sense that both template can be specialized to
match the
call. But then, the "more specific" code rule apply, it's the same
principle
that say that if you have:
void f(std::vector<int>&, std::vector<int> const&) and
template<typename T> void f(T&, const T&);
you choose the first one, because it was specificaly conceived for
vectors and
not for "some type" T.
Here, we have the choice betwen a template designed for two identical
parameter
(more or less) which is more specific, wrt that call, than two possibly
distincts
types.
To decide which is more specific/specialized, one can consider a
template,
bind it's argument to some invented type and see if it can call the
other
with it:
template<typename T1, typename T2> void f_1(T1&, const T2&);
template<typename T> void f_2(T&, const T&);
->
struct T1{}; struct T2 {};
void f_1(T1& t1, const T2& t2) {
f_2(t1, t2); // cannot call
}
->
struct T {};
struct F_2(T& t1, const T& t2) {
f_1(t1,t2); // can call
}
so f_1 is more specialized.
Alain
> To my astonishment, g++, mwcc, and bcc32 all call the second f, the one
> with only a single type argument. Can somebody please explain why the
> second f is preferred to the first one?
>
> Thanks,
>
> Scott
>
> ---
> [ 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 ]
> [ --- Please see the FAQ before posting. --- ]
> [ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
---
[ 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 ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: smeyers@aristeia.com (Scott Meyers)
Date: 2000/07/02 Raw View
Many thanks to everybody who clued me in about the rules for the partial
ordering of overloaded template functions. One of these days I really must
read chapter 14 of the standard, but I find all those template rules so darn
intimidating...
Thanks again,
Scott
---
[ 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 ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]