Topic: Function templates with non-type parameters
Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/06/16 Raw View
In article <3r52bt$h4s@zip.eecs.umich.edu>,
Michael Rice <mrice@quip.eecs.umich.edu> wrote:
>Section 14.3.2 of the draft has the following example:
>
>template<int i> int fac() { return i>1 ? i*fac<i-1>() : 1; }
>int fac<0>() { return 1; }
>int f()
>{
> return fac<17>();
>}
>
>Wouldn't this instantiate 17 separate functions?
Yes.
>Is so, what a terrible example.
Why? It illustrates recursive template instantiation
with a familiar and very compact example, which is the purpose.
>The ARM disallowed non-type parameters for
>function templates; now they are apparently legal. My question is,
>why do we need this.
What excuse could we have for such non-orthogonality?
You can write:
X<1> x; // a class
^^^^
it makes sense to be able to write:
int (*pf)() = &fac<1>; // a function
^^^^^^
since you can write:
Y<int> y; // a class
^^^^^^
int (*pg)() = &g<int>; // a function
^^^^^^
>What is the rationale for allowing this, and what was the rationale for the
>ARM disallowing it?
An example of where it is useful is:
template<int n, class T> struct X { T data[n]; };
template<int n, class T> X<n,T> make(T t)
{
X<T, n> x;
for(int i=0; i<n; ++i) x.data[i]=t;
return x;
}
... make<20>(1) ... // makes 20 ints of value 1 in an array
// wrapped in an X struct
Being able to build a hierarchical family of parameterised functions
like this is useful. In particular:
template<int n, class T> struct X { X() {} };
Now how _else_ can you create an appropriate X object than by
calling the constructor? How would you make a temporary one
other than like:
.. X<20,int>() ...
Isn't that a "function call" -- where the function happens to
be a constructor?
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA Phone: 61-2-566-2189
Author: lanneer@imec.be (Dirk Lanneer)
Date: 1995/06/16 Raw View
I have some further question related to non-type template parameters. The
draft version of the C++ Standard clearly disallows the following construct:
template <int i> class A { ... };
template <int i> void f(A<i+1>);
It is not clear to me whether the C++ Standard designers intend to allow the
following construct:
template <int i> class A { ...};
template <int i, int j> A<i+j> f(A<i>,A<j>);
--
--------------------------------------------------- Dirk Lanneer -------------
IMEC
PHONE : +32/16/28.12.58 Kapeldreef 75
FAX : +32/16/28.15.15 B-3001 Leuven
E-MAIL : lanneer@imec.be Belgium
Author: schuenem@informatik.tu-muenchen.de (Ulf Schuenemann)
Date: 1995/06/12 Raw View
In article <3r52bt$h4s@zip.eecs.umich.edu>, mrice@quip.eecs.umich.edu (Michael Rice) writes:
|> ... My question is,
|> why do we need this. When is f<int>() better that f(int)?
Just two thoughts:
1. The compiler can inline the whole recursion:
template<int i> inline int fac() { return i>1 ? i*fac<i-1>() : 1; }
int fac<0>() { return 1; }
In a call fac<17>() the parameter of the template is known at compiletime.
fac<17> is instantiated inline with the call fac<16>() within it. fac<16>
in turn is instantiated inline with fac<15> and so on up to inlining fac<0>.
This gives one fat portion of inline code. But its a little bit faster
then a recursive functioncall.
2. Such a template would be a real advantage if there where template-objects:
template<int i> const int fac = i>1 ? i*fac<i-1> : 1;
const int fac<0> = 1;
Then the compiler could evaluate fac<17> once and AT COMPILETIME, allowing
float some_array [ fac<7> ];
( fac<17> may get a little too big: 355687428096000 ;-) )
N.B. Only the fac<>s [ 0 .. fac<maxNeeded> ] get instantiated and evaluated.
[ Sorry just dreaming ]
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Fakult t f r Informatik, Technische Universit t M nchen, Germany.
email: schuenem@informatik.tu-muenchen.de
Author: swf@ElSegundoCA.ATTGIS.COM (Stan Friesen)
Date: 1995/06/09 Raw View
In article <D9tn2L.25G@edg.com>, jhs@edg.com (John H. Spicer) writes:
|>
|> >What is the rationale for allowing this, and what was the rationale for the
|> >ARM disallowing it?
|>
|> I don't know why the ARM disallowed it. I suspect that it was
|> because the ARM description of templates preceded any implementation,
|> and there were implementation concerns. ...
Actually the reason was fairly simple:
A function template with only type parameters (and meeting certain other
restriction) can be resolved to the correct specialization purely by the
types of its actual arguments, so it was never necessary to use the <>
notation when actually *calling* a function based on a template.
Since the Draft Standard now allows the <> notation when calling a function,
the restriction is no longer useful.
--
swf@elsegundoca.attgis.com sarima@netcom.com
The peace of God be with you.
Author: jhs@edg.com (John H. Spicer)
Date: 1995/06/10 Raw View
In article <9506091432.AA01948@mailhost.ElSegundoCA.ATTGIS.COM> swf@ElSegundoCA.ATTGIS.COM writes:
>In article <D9tn2L.25G@edg.com>, jhs@edg.com (John H. Spicer) writes:
>|>
>|> >What is the rationale for allowing this, and what was the rationale for the
>|> >ARM disallowing it?
>|>
>|> I don't know why the ARM disallowed it. I suspect that it was
>|> because the ARM description of templates preceded any implementation,
>|> and there were implementation concerns. ...
>
>Actually the reason was fairly simple:
>A function template with only type parameters (and meeting certain other
>restriction) can be resolved to the correct specialization purely by the
>types of its actual arguments, so it was never necessary to use the <>
>notation when actually *calling* a function based on a template.
>
>Since the Draft Standard now allows the <> notation when calling a function,
>the restriction is no longer useful.
>
The <> notation has nothing to do with it.
Nontype parameters for function templates were added to the language
a year before the <> notation was added.
John Spicer
Edison Design Group
Author: jhs@edg.com (John H. Spicer)
Date: 1995/06/07 Raw View
In article <3r52bt$h4s@zip.eecs.umich.edu> mrice@quip.eecs.umich.edu (Michael Rice) writes:
>Section 14.3.2 of the draft has the following example:
>
>template<int i> int fac() { return i>1 ? i*fac<i-1>() : 1; }
>
>int fac<0>() { return 1; }
>
>int f()
>{
> return fac<17>();
>}
>
>Wouldn't this instantiate 17 separate functions? If not, I guess I
>don't understand what is going on. Is so, what a terrible example.
It may not be a very good example of how nontype template parameters
are used on function templates, but that is not what the example is
intended to illustrate. The example shows that recursive instantiations
are permitted. Recursive instantiations that do terminate at some
point are possible in "real world" applications, but rare. Yes,
the example you show is contrived, but I think it accomplishes what
it set out to do.
> The ARM disallowed non-type parameters for
>function templates; now they are apparently legal. My question is,
>why do we need this. When is f<int>() better that f(int)?
>
Nontype parameters for function templates are needed to be able to write
template functions that operator on template classes that use nontype
template parameters. For example:
template <int I> struct A {
friend A operator+(const A&, const A&);
};
template <int I> A<I> operator+(const A<I>&, const A<I>&)
{
A<I> result;
// Code to add an A to an A
return result;
}
int main()
{
A<1> a1, a2, a3;
a3 = a1 + a2;
}
Anyone who has written a template class that uses a nontype parameter
has probably run into this restriction at some point.
This was added by X3J16/WG21 when it was determined it was needed for
the Bits class that was then part of the WP.
>What is the rationale for allowing this, and what was the rationale for the
>ARM disallowing it?
I don't know why the ARM disallowed it. I suspect that it was
because the ARM description of templates preceded any implementation,
and there were implementation concerns. There are a number of restrictions
on how nontype parameters may be used in function declarations that are
needed to make implementation possible.
John Spicer
Edison Design Group
Author: mrice@quip.eecs.umich.edu (Michael Rice)
Date: 1995/06/07 Raw View
Section 14.3.2 of the draft has the following example:
template<int i> int fac() { return i>1 ? i*fac<i-1>() : 1; }
int fac<0>() { return 1; }
int f()
{
return fac<17>();
}
Wouldn't this instantiate 17 separate functions? If not, I guess I
don't understand what is going on. Is so, what a terrible example.
Obviously the traditional:
int fac(int i)
{
return i>1 ? i*fac(i-1) : 1;
}
int f() { return fac(17); }
would make more sense. The ARM disallowed non-type parameters for
function templates; now they are apparently legal. My question is,
why do we need this. When is f<int>() better that f(int)?
What is the rationale for allowing this, and what was the rationale for the
ARM disallowing it?