Topic: Template questions
Author: gp1@paradise.net.nz (Graeme Prentice)
Date: Sun, 11 May 2003 19:22:56 +0000 (UTC) Raw View
On Wed, 7 May 2003 21:04:43 +0000 (UTC), dishsi@tin.it ("Gianluca
Silvestri") wrote:
>Hi everyone.
>I can't understand the meaning of these two paragraphs from the Standard:
>
>14.5.4/8
>"A nontype argument is nonspecialized if it is the name of a nontype
>parameter. All other nontype arguments are specialized."
>From para 4
template<class T1, class T2, int I> class A { }; // #1
template<class T, int I> class A<T, T*, I> { }; // #2
template<class T1, class T2, int I> class A<T1*, T2, I> { }; // #3
template<class T> class A<int, T*, 5> { }; // #4
template<class T1, class T2, int I> class A<T1, T2*, I> { }; // #5
In line #2, the argument list is T,T*, I
I is the name of a non type parameter so is non specialised
In line #4, the argument list is int, T*, 5
5 is not the name of a non type parameter, so is specialised
>
>14.5.4.1/3
>"A nontype template argument can also be deduced from the value of an actual
>template argument of a nontype parameter of the primary template. [Example:
>the declaration of a2 above. ]"
>From para 2
A<int, int, 1> a1; // uses #1
A<int, int*, 1> a2; // uses #2, T is int, I is 1
A<int, char*, 5> a3; // uses #4, T is char
A<int, char*, 1> a4; // uses #5, T1 is int, T2 is char, I is 1
A<int*, int*, 2> a5; // ambiguous: matches #3 and #5
In "template argument deduction", it is the template parameter
types/values that are being deduced, not the arguments, even though the
C++ standard uses terminology that suggests otherwise (as in para 3
above). In line #2 above (declaration of a2), the specialisation #2
(from para 4) is used and the non type template parameter I (the second
parameter of the partial specialisation) is deduced as having a value of
5 - however the 5 is the third of the "actual template arguments" and
corresponds to the third parameter of the primary template, but is used
to deduce the second parameter of the partial specialisation.
>From para 4
template<class T1, class T2, int I> class A { }; // #1
template<class T, int I> class A<T, T*, I> { }; // #2
#1 is the primary template and has a template parameter list of
<class T1, class T2,int I>
#2 is the partial specialisation and has a template parameter list of
<class T, int I>
and a template argument list of
<T, T*, I>
The declaration
A<int, int*, 1> a2; // uses #2, T is int, I is 1
has an actual template argument list of int,int*,1.
Graeme
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dishsi@tin.it (Gianluca Silvestri)
Date: Mon, 12 May 2003 18:21:07 +0000 (UTC) Raw View
gp1@paradise.net.nz (Graeme Prentice) wrote in message news:<hrasbvoj79usbe85f5lcn1rb53m0s16cl0@4ax.com>...
> >From para 4
> template<class T1, class T2, int I> class A { }; // #1
> template<class T, int I> class A<T, T*, I> { }; // #2
> template<class T1, class T2, int I> class A<T1*, T2, I> { }; // #3
> template<class T> class A<int, T*, 5> { }; // #4
> template<class T1, class T2, int I> class A<T1, T2*, I> { }; // #5
>
>
[snip]
> >14.5.4.1/3
> >"A nontype template argument can also be deduced from the value of an actual
> >template argument of a nontype parameter of the primary template. [Example:
> >the declaration of a2 above. ]"
>
[snip]
> Graeme
>
> ---
> [ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Thanks,
Gianluca
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dishsi@tin.it ("Gianluca Silvestri")
Date: Wed, 7 May 2003 21:04:43 +0000 (UTC) Raw View
Hi everyone.
I can't understand the meaning of these two paragraphs from the Standard:
14.5.4/8
"A nontype argument is nonspecialized if it is the name of a nontype
parameter. All other nontype arguments are specialized."
14.5.4.1/3
"A nontype template argument can also be deduced from the value of an actual
template argument of a nontype parameter of the primary template. [Example:
the declaration of a2 above. ]"
Can someone explain them with examples ?
Thanks,
Gianluca
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1995/11/18 Raw View
Bob Kline (bkline@cortex.nlm.nih.gov) wrote:
|> A couple of questions about situations in which I'm not sure why
|> the compiler (Sun's CC in this case) is rejecting some template code.
|> The first case involves the following code:
|> template<size_t N> class bitset { ... };
|> bitset<6> bs;
|> The compiler complains:
|> Error: Template parameter N requires an expression of type unsigned.
In the ARM, templates always required an exact type match, with no
conversion allowed. I believe that the current draft has lessened this
stricture somewhat, although I don't know whether this precise case or
not is affected.
I doubt that many compilers are up to date on this, so even if the draft
says its OK, you may have to wait for a later release of your compiler.
|> Two questions about this one: is this correct-- does the draft really
|> not allow an implicit conversion of the template argument here? And
|> if it is correct, would it not be prudent to amend the bitset<N>
|> class in the draft standard library to take an int instead of a
|> size_t template argument? Template syntax is ugly enough already!
|> :->}
In my bitset, I used int, to simplify life. BUT...
My targets are all 32 bit. Most of the time, my bitset ends up being
instantiate over UCHAR_MAX+1 (and the resulting class ends up being
called SetOfChar:-).) Fine so far. But imagine a 16 bit machine using
Unicode (16 bit wchar_t characters). An int won't cut it. For that
matter, I'm not sure a size_t will. You need 65536, and I think that in
many cases, 65535 is all you get.
So I agree that it should be changed from size_t. But the new type
should be unsigned long, not int.
(For the record, well over 50% of all of my bitset's have been
SetOfChar. And in light of the above, I'm changing my bitset to use
unsigned long immediatly.)
|> Here's the other case:
|> template<size_t N>
|> bitset<N> operator&(const bitset<N>& lhs, const bitset<N>& rhs)
|> {
|> return bitset<N>(lhs) &= rhs;
|> }
|> To which the compiler responds:
|> "./bitset", line 333: Error: The template argument N is not a type.
|> Why is this? The same compiler accepts the "template<size_t N>
|> class bitset { ... }" quoted above, so I'm puzzled. However, this
|> isn't the only compiler which accepts the first use of a non-type
|> template argument and rejects the second, so I'm beginning to suspect
|> I'm just missing something obvious. Can someone point it out
|> to me, please?
Again, language change. The ARM only allowed type arguments for
template functions, since it was unclear at the time when and if it
could deduce the correct function if non-type parameters were used. The
standards committee extended this to allow for non-type parameters in
certain cases. I don't know the exact rules, but the above is certainly
legal *now*.
Again, wait 'til next release:-).
--
James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils, itudes et rialisations en logiciel orienti objet --
-- A la recherche d'une activiti dans une region francophone
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: jamshid@emx.cc.utexas.edu (Jamshid Afshar)
Date: 28 Sep 1993 21:11:48 -0500 Raw View
In article <27mejn$aup@agate.berkeley.edu>,
Paul N. Hilfinger <hilfinger@CS.Berkeley.EDU> wrote:
: template <class T> struct A {
: A(T x);
: A(const A<T>& x);
: };
: template <class T> void foo(const A<T>& x);
: void f() {
: A<int> x;
: foo(x);
: }
: The ARM (14.4c) says that the template match for foo must be exact,
: without even trivial conversions. This seems to make the call on
: foo here illegal, because the trivial conversion A<int> --> const A<int>&
: is necessary. Was this intended? If not, how should the ARM
: read?
That's what's written and what was intended. Stroustrup was purposely
being very cautious. Relaxing this rule to at least allow trivial
conversions is a very likely change from the ARM (see Lippman's 2nd Ed
9.3). Lippman also mentions the possibility of allowing:
template<class T> struct B : A<T> {};
void g() {
B<int> x;
foo(x); // B<int> => `const A<int>&'
}
That is, template functions will even match template arguments via
standard conversions. I'm not sure whether standard conversions will
be performed for non-template arguments, though. BC++ for OS/2, which
claims to implement the above "cfront" extension, does not allow:
template<class T> void output(Base&, const A<T>&);
void g(Derived& d) {
A<int> x;
output(d,x); // legal?
}
I hope BC++ for OS/2 is being overly cautious because
ostream operator<<(ostream&, const List<String>&);
is not something I want to be required to declare everytime I do
cout << strlist;
: void foo(const A<int>& x);
: void f() {
: foo(3);
: }
: The explicit instantiation of foo here makes the call on foo(3)
: work, correct? That is, 3 is converted by the first constructor
: in A<int>, right? Furthermore, this would be illegal without the
: explicit declaration of foo, correct (exact template matching
: required, again).
Right.
: void f() {
: A<int> x;
: foo(x);
: foo(3);
: }
:
: Here there is no explicit declaration of foo on A<int>. However,
: there is a call foo(x) that does instantiate foo on A<int>. The
: ARM says (14.5c) that calling a function template "constitutes a
: declaration" of a template function (in this case, foo on A<int>).
: Does the existence of this (implicit) declaration make the
: following call on foo(3) legal, as did the explicit declaration in
: the first part of this question?
Don't know. Also, what if foo() is declared as a friend inside of
A<T>? Does that declaration make foo() match arguments like an
explicitly declared function (ie, instantiate it)?
: void foo(const A<int>& x);
: void f() {
: foo(3u);
: }
: Is this legal? There is an explicit version of foo around and
: 3u can be converted to type int, matching the first constructor in
: A. However, is there an instantiation of this constructor
: around, [...]
No, the above is fine even under the current strict rules. I don't
think it was ever intended that class template member function would
require exact argument matches.
I'm not a member of XJ316 (though I play one on TV), but I've been
told that the Novemeber meeting will discuss a lot of template issues.
Expect more decisions then. Let your compiler writers know what
issues you want resolved quickly and what outcomes you desire.
Jamshid Afshar
jamshid@emx.cc.utexas.edu
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Thu, 30 Sep 1993 07:46:47 GMT Raw View
In article <28aqt4INNpfc@emx.cc.utexas.edu> jamshid@emx.cc.utexas.edu (Jamshid Afshar) writes:
>In article <27mejn$aup@agate.berkeley.edu>,
>Paul N. Hilfinger <hilfinger@CS.Berkeley.EDU> wrote:
>: template <class T> struct A {
>: A(T x);
>: A(const A<T>& x);
>: };
>: template <class T> void foo(const A<T>& x);
>: void f() {
>: A<int> x;
>: foo(x);
>: }
>: The ARM (14.4c) says that the template match for foo must be exact,
>: without even trivial conversions. This seems to make the call on
>: foo here illegal, because the trivial conversion A<int> --> const A<int>&
>: is necessary. Was this intended? If not, how should the ARM
>: read?
>
>That's what's written and what was intended. Stroustrup was purposely
>being very cautious. Relaxing this rule to at least allow trivial
>conversions is a very likely change from the ARM (see Lippman's 2nd Ed 9.3).
Sorry to interrupt you fellows, but I think you may have both read the ARM
wrong.
The rule which Paul cited is given on the third to last line on page 345
of the ARM. Note that it includes a reference to (13.2) when it mentions
the term "exact match".
If you look over in 13.2, you will note that "exact match" is defined as
one which may *include* trivial conversions. (See page 318.)
With regard to Jamshid's point about Lippman's suggestion that the rules
may be loosened, Lippman did suggest this (I think) but the "loosening"
in question would be to allow a match of a template formal of type base*
with a template actual of type derived*... but that involves a *standard*
conversion, not a trivial one.
--
-- Ronald F. Guilmette ------------------------------------------------------
------ domain address: rfg@netcom.com ---------------------------------------
------ uucp address: ...!uunet!netcom.com!rfg -------------------------------
Author: jamshid@emx.cc.utexas.edu (Jamshid Afshar)
Date: 30 Sep 1993 12:08:17 -0500 Raw View
In article <rfgCE5pM0.89L@netcom.com>,
Ronald F. Guilmette <rfg@netcom.com> wrote:
>In article <28aqt4INNpfc@emx.cc.utexas.edu> jamshid@emx.cc.utexas.edu (Jamshid Afshar) writes:
>>In article <27mejn$aup@agate.berkeley.edu>,
>>Paul N. Hilfinger <hilfinger@CS.Berkeley.EDU> wrote:
>>: The ARM (14.4c) says that the template match for foo must be exact,
>>: without even trivial conversions.
>>[...] Relaxing this rule to at least allow trivial
>>conversions is a very likely change from the ARM (see Lippman's 2nd Ed 9.3).
>
>Sorry to interrupt you fellows, but I think you may have both read the ARM
>wrong.
>The rule which Paul cited is given on the third to last line on page 345
>of the ARM. Note that it includes a reference to (13.2) when it mentions
>the term "exact match".
Did you not see my followup to your article the last time you made
this mistake? See the appended article and the rest of 13.2 -- the
ARM does not allow trivial conversions when matching a template
function.
>With regard to Jamshid's point about Lippman's suggestion that the rules
>may be loosened, Lippman did suggest this (I think) but the "loosening"
>in question would be to allow a match of a template formal of type base*
>with a template actual of type derived*... but that involves a *standard*
>conversion, not a trivial one.
Right, but isn't that what I wrote?
[...] Relaxing this rule to at least allow trivial
conversions is a very likely change from the ARM (see Lippman's 2nd Ed
9.3). Lippman also mentions the possibility of allowing: [...]
^^^^
That is, template functions will even match template arguments via
standard conversions.
Here's the article where I cleared up Ron's misreading the last time.
Don't make me have to tell you again. ;-)
---June 1993 article on this subject---
From: jamshid@emx.cc.utexas.edu (Jamshid Afshar)
Newsgroups: comp.std.c++
Subject: Re: Templates and trivial conversions?
Date: 7 Jun 1993 21:35:52 -0500
Organization: The University of Texas at Austin, Austin, Texas
Lines: 88
Message-ID: <1v0tu8INNiiv@emx.cc.utexas.edu>
References: <1993Jun6.171544.15025@cdf.toronto.edu> <rfgC89yLA.I3y@netcom.com>
NNTP-Posting-Host: emx.cc.utexas.edu
Summary: reread: ARM says no triv. convs; will ANSI allow stand. convs?
In article <rfgC89yLA.I3y@netcom.com> rfg@netcom.com (Ronald F. Guilmette) writes:
>In article <1993Jun6.171544.15025@cdf.toronto.edu> g2devi@cdf.toronto.edu (Deviasse Robert N.) writes:
>>I know that ARM explicitly states that not even trivial conversions are
>>applied in order to match a template...
>
>Buzzztt! Wrong.
No, Robert is right about that. ANSI C++ might change this ARM rule,
though.
>Tha ARM talks about an "exact match" between the types of template formals
>and the types of template actuals... where the term "exact match" is
>defined in the chapter on overloading.
>Surprizing as it may be to some, you can have an "exact match" even though
>you use some trivial conversions.
You're right that an "exact match" as defined by the ARM 13.2 includes
trivial conversions, but take a closer look at ARM 14.4c:
[...] Overloading resolution for template functions and other
functions of the same name is done in three steps:
[1] Look for an exact match on functions; if found, call it.
[2] Look for a function template from which a function that
can be called with an exact match can be generated; if
^^^^^
found, call it.
[3] Try ordinary overloading resolution for the functions;
if a function is found, call it.
[...]
A match on a template (step [2]) implies that a specific
template function with arguments that exactly matches the types
of the arguments will be generated. Not even trivial conversions
^^^^^^^^^^^^^^^^^^^^^^^^
will be applied in this case.
The underlined "exact" is therefore meant literally. Lippman writes
in the _C++ Primer 2nd Ed_ 4.2 p199 that performing trivial
conversions is a likely ANSI extension. The BC++ for OS/2 README file
states that it now performs trivial conversions to match template
functions for compatibility with this CFRONT 3.0 "extension". The
README further states:
2) Derived class pointer or references arguments are permitted to
match their public base classes. For example:
template<class T> class B {};
template<class T> class D : public B<T> {};
template<class T> void foo(B<T> *b);
foo(new D<int>); // This is illegal under ANSI C++: unresolved
// foo(D<int> *). However, Borland C++ now
// allows foo(B<int> *) to be called.
This possible ANSI C++ extension is also implemented by CFRONT and
discussed in Primer2 9.3 p493. That's great, but I'm disturbed by the
README's sidenote:
The conversion from derived class to base class is allowed
only for template parameters, non-template parameters still
require exact matches. For example:
class B {};
class D : public B {};
template<class T> void bar(T ignored, B *b);
bar(0, new D); // Illegal under CFRONT 3.0, ANSI C++ and
// Borland C++: unresolved external bar(int, D *),
// D * -> B * is not considered an exact match.
Is allowing this not a likely ANSI C++ extension, or is Borland just
being very cautious? I was hoping ANSI would fix the common error:
#include <iostream.h>
template<class T> class List {/*...*/};
template<class T> ostream& operator<<(ostream&,const List<T>&);
main() {
List<int> list;
//...
cout << list << endl; // error (unfortunately)
}
I believe CFRONT implements this extension, but Borland and gcc do
not.
Jamshid Afshar
jamshid@emx.utexas.edu
Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Fri, 1 Oct 1993 09:52:36 GMT Raw View
In article <28f3q1INN8ei@emx.cc.utexas.edu> jamshid@emx.cc.utexas.edu (Jamshid Afshar) writes:
>In article <rfgCE5pM0.89L@netcom.com>,
>Ronald F. Guilmette <rfg@netcom.com> wrote:
>>In article <28aqt4INNpfc@emx.cc.utexas.edu> jamshid@emx.cc.utexas.edu (Jamshid Afshar) writes:
>>>In article <27mejn$aup@agate.berkeley.edu>,
>>>Paul N. Hilfinger <hilfinger@CS.Berkeley.EDU> wrote:
>>>: The ARM (14.4c) says that the template match for foo must be exact,
>>>: without even trivial conversions.
>>>[...] Relaxing this rule to at least allow trivial
>>>conversions is a very likely change from the ARM (see Lippman's 2nd Ed 9.3).
>>
>>Sorry to interrupt you fellows, but I think you may have both read the ARM
>>wrong.
>>The rule which Paul cited is given on the third to last line on page 345
>>of the ARM. Note that it includes a reference to (13.2) when it mentions
>>the term "exact match".
>
>Did you not see my followup to your article the last time you made
>this mistake? See the appended article and the rest of 13.2 -- the
>ARM does not allow trivial conversions when matching a template
>function.
You're Right. Sorry. I keep forgetting to turn over the page from 345
to 346. (the stuff I mentioned is written on the bottom of 345, and the
additional caveat you mentioned is over on the top of 346.)
By the way, is it just me, or does it seem to be just the least bit
confusing for the ARM to first say "exact match (13.2)" and *then* to
say the equivalent of "No... this time I *really* mean exact match!"
Maybe someone should suggest to X3J16 the use of some better term in
place of "exact match". How about "trivial match"?
--
-- Ronald F. Guilmette ------------------------------------------------------
------ domain address: rfg@netcom.com ---------------------------------------
------ uucp address: ...!uunet!netcom.com!rfg -------------------------------
Author: hilfingr@tully.CS.Berkeley.EDU (Paul N. Hilfinger)
Date: 21 Sep 1993 08:39:19 GMT Raw View
For all of the following, I am interested in what the standard says
(should say, will say, etc.), and NOT what any implementation does. (I
have this quixotic notion that semantic questions about a language
are not empirical). Thanks for any responses.
Consider the following declarations and definitions.
template <class T>
class A {
public:
A(T x) : ... { ... }
A(const A<T>& x) : ... { ... }
...
};
template <class T>
void foo(const A<T>& x) { ... }
// OTHER STUFF
Question I.
Suppose we replace // OTHER STUFF with the following.
void f()
{
A<int> x;
foo(x);
}
The ARM (14.4c) says that the template match for foo must be exact,
without even trivial conversions. This seems to make the call on
foo here illegal, because the trivial conversion A<int> --> const A<int>&
is necessary. Was this intended? If not, how should the ARM
read?
Question II.
I'll now assume that the program in I was supposed to work.
Now replace // OTHER STUFF with
void foo(const A<int>& x);
void f()
{
foo(3);
}
The explicit instantiation of foo here makes the call on foo(3)
work, correct? That is, 3 is converted by the first constructor
in A<int>, right? Furthermore, this would be illegal without the
explicit declaration of foo, correct (exact template matching
required, again). OK. Now suppose that I instead write
void f()
{
A<int> x;
foo(x);
foo(3);
}
Here there is no explicit declaration of foo on A<int>. However,
there is a call foo(x) that does instantiate foo on A<int>. The
ARM says (14.5c) that calling a function template "constitutes a
declaration" of a template function (in this case, foo on A<int>).
Does the existence of this (implicit) declaration make the
following call on foo(3) legal, as did the explicit declaration in
the first part of this question?
Question III.
Suppose we replace // OTHER STUFF with the following.
void foo(const A<int>& x);
void f()
{
foo(3u);
}
Is this legal? There is an explicit version of foo around and
3u can be converted to type int, matching the first constructor in
A. However, is there an instantiation of this constructor
around, or does the need for conversion of 3u to A<int> require
an additional template instantiation? If so, then the fact that a
conversion is required to get 3u to 3 would seem to prevent such
an instantiation.
Paul Hilfinger