Topic: Recursive Template? Are you sure?
Author: xjzhu@math.uwaterloo.ca (Xiaojun Zhu)
Date: Mon, 23 Nov 1992 17:58:45 GMT Raw View
Hi, there:
While everybody is so hot on the topic about "Recursive template",
I can't seem to make the following code compile under AT&T C++ V3.0.
Can comeone enlight me about this? (or maybe the original creator of
this piece of code) It seems to me that you have to instantiate every
class which gets involed in. For example, in this case, you have to
instantiate class Factorial<1>, class Factorial<2>, ..., class
Factorial<5>, but if this is the case, what's the so good about
this recursive template? I don't get the point.
*********Code Segment follows************
#include <iostream.h>
template<int n> class Factorial
{
public:
int eval() { return n*Factorial<n-1>.eval(); }
};
class Factorial<0>
{
public:
int eval() { return 1; }
};
int main()
{
Factorial<6> f6;
cout << f6.eval() << endl;
return 0;
}
********** Code Segment Ends **********
--------------------------------------------------------------
A template version of signature class is under repair.
Symptom: It dies without a warning if I use certain class
as an argument.
xjzhu@math.uwaterloo.ca
--------------------------------------------------------------
Author: jamshid@ut-emx.uucp (Jamshid Afshar)
Date: 1 Dec 92 04:33:31 GMT Raw View
Followups are redirected to comp.lang.c++ only.
In article <By6KLy.1yB@math.uwaterloo.ca> xjzhu@math.uwaterloo.ca (Xiaojun Zhu) writes:
>While everybody is so hot on the topic about "Recursive template",
>I can't seem to make the following code compile under AT&T C++ V3.0.
>Can comeone enlight me about this? (or maybe the original creator of
>this piece of code) [...]
That code that was recently posted was slightly off. While I doubt I
was the first to make a Factorial template, I did post the appended
article back in March. The correct example is at the end. Btw,
there are situations (unlike this one) where a recursive template is
truly useful, practical, and possibly even elegant.
From: jamshid@ut-emx.uucp (Jamshid Afshar)
Newsgroups: comp.std.c++
Subject: Re: recursive function templates
Summary: templates: they're not just for data structures anymore
Message-ID: <68499@ut-emx.uucp>
Date: 16 Mar 92 10:40:09 GMT
References: <1992Mar11.212207.20275@watmath.waterloo.edu>
Organization: The University of Texas at Austin; Austin, Texas
Lines: 109
In article <1992Mar11.212207.20275@watmath.waterloo.edu>
gjditchfield@watmsg.waterloo.edu (Glen Ditchfield) writes:
>...
>template<class T> void f(T t_p, long l) {
> struct s { T t_f } temp = {t_p};
> if (l > 0)
> f(temp, l - 1);
Cool!
>}
>extern long random();
>void main() {
> f(3.14, random());
>}
>... and there is
>no static way to put a useful upper bound on the number of generations
>needed.
You're right, in your example there isn't a way to make it stop
instantiating template functions. You can stop template expansion by
`specializing', but you can't specialize for local types. Try
something like like the following instead:
//---begin
#include <iostream.h>
template<class M> struct S {
M m;
S(const M& a_m) : m(a_m) {}
};
template<class T> void f(T t, long l) {
S<T> tmp(t); // BC++ erroneously(?) broke on `S<T> tmp = { t };'
cout << &t << '\t' << l << '\t' << &tmp << endl;
if (l>0)
f(tmp, l-1);
}
// a specialization of `f()'
void f(S< S< S< S< S<double> > > > > t, long l) {
cout << &t << '\t' << l << '\t' << "STOP" << endl;
}
main() {
double d = 3.141569;
f(d, 5L); // go from 5 to 0
}
//---end
>I don't see anything in the ARM that makes constructs like f illegal.
I also can't find anything explicitly making it illegal. Another
situation that could make a C++ compiler go into an infinite loop is:
class Test {
public:
// or instead loop through another class defining `Test& operator->()'
Test& operator->() { return *this; }
int i;
};
main() { Test t; t->i = 0; return 0; }
I don't know if ANSI will, or even how exactly they would, specify
these kinds of things as having undefined results. Would compilers be
required to diagnose them (like ANSI C requires for some constructs),
or could the compiler simply hang (ie, undefined compile-time
results)? Is there anything analogous to this in ANSI C?
Btw, the appended has probably already been discovered by countless
others, but I think it's really neat and it helped me find a couple of
bizarre Borland C++ 3.0 bugs, so try it with your compilers.
Jamshid Afshar
jamshid@emx.utexas.edu
//---begin fact.cpp ---
// `Factorial<n>::compute()' is a cute way to compute at compile-time
// the factorial of a constant long `n'.
// Btw, compute() must be member func since template function parameters
// can only be types, not expressions. Lippman's says removing this
// restriction is a likely ANSI C++ proposal, but the outcome is not clear.
#include <iostream.h>
template<unsigned long N> struct Factorial {
static unsigned long compute() { return N*Factorial<N-1>::compute(); }
};
struct Factorial<0UL> { // BC++ requires `L'
static unsigned long compute() { return 1; }
};
// I think you should be able to just define the following instead
// of the entire class, but Borland C++ 3.0 run out of memory.
// inline unsigned long Factorial<0UL>::compute() { return 1; }
main() {
// BC++ starts freaking out sometimes if J>10
const unsigned long J = 10; // must be compile-time constant, of course
unsigned long f = 1, i=J;
while (i>0) f*=i--;
cout << "factorial(" << J << ") is " << f << endl;
cout << J << "! is " << Factorial<J>::compute() << endl;
return 0;
}
//---end fact.cpp ---