static int getCount() { return count; }
};
int CountedClass::count = 0;
int main() {
CountedClass a;
cout << CountedClass::getCount() << endl; // 1
CountedClass b;
cout << CountedClass::getCount() << endl; // 2
{ // an arbitrary scope:
CountedClass c(b);
cout << CountedClass::getCount() << endl; // 3
a = c;
cout << CountedClass::getCount() << endl; // 3
}
cout << CountedClass::getCount() << endl; // 2
} ///:~.
All constructors of CountedClass increment the static data member count, and the destructor decrements it. The static member function getCount( ) yields the number of current objects whenever it called.
It would be tremendously tedious to have to manually add these members every time you wanted to add object counting to a class. What is the usual object-oriented device to which one turns to repeat or share code? It’s inheritance, of course, which, unfortunately, is only half a solution in this case. Observe what happens when we collect the counting logic into a base class.
//: C05:CountedClass2.cpp
// Erroneous attempt to count objects
#include <iostream>
using namespace std;
class Counted {
static int count;
public:
Counted() { ++count; }
Counted(const Counted&) { ++count; }
~Counted() { --count; }
static int getCount() { return count; }
};
int Counted::count = 0;
class CountedClass : public Counted {};
class CountedClass2 : public Counted {};
int main() {
CountedClass a;
cout << CountedClass::getCount() << endl; // 1
CountedClass b;
cout << CountedClass::getCount() << endl; // 2
CountedClass2 c;
cout << CountedClass2::getCount() << endl; // 3 (Error)
} ///:~
All classes that derive from Counted share the same, single static data member, so the number of objects is tracked collectively across all classes in the Counted hierarchy. What is needed is a way to automatically generate a different base class for each derived class. This is accomplished by the curious template construct illustrated below:.
//: C05:CountedClass3.cpp
#include <iostream>
using namespace std;
template<class T>
class Counted {
static int count;
public:
Counted() { ++count; }
Counted(const Counted<T>&) { ++count; }
~Counted() { --count; }
static int getCount() { return count; }
};
template<class T>
int Counted<T>::count = 0;
// Curious class definitions
class CountedClass : public Counted<CountedClass> {};
class CountedClass2 : public Counted<CountedClass2> {};
int main() {
CountedClass a;
cout << CountedClass::getCount() << endl; // 1
CountedClass b;
cout << CountedClass::getCount() << endl; // 2
CountedClass2 c;
cout << CountedClass2::getCount() << endl; // 1 (!)
} ///:~.
Each derived class derives from a unique base class that is determined by using itself (the derived class) as a template parameter! This may seem like a circular definition, and it would be, had any base class members used the template argument in a computation. Since all data members of Counted are not dependent on T, its size (which is zero!) is known when the template is parsed. It doesn’t matter, therefore, which argument is used to instantiate Counted; its size is always the same. Therefore, any derivation from an instance of Counted can be completed when it is parsed, and there is no recursion. Since each base class is unique, it has its own static data, thus constituting a handy technique for adding counting to any class whatsoever. Jim Coplien was the first to mention this interesting derivation idiom in print, which he cited in an article, entitled "Curiously Recurring Template Patterns."[ ][65]
Template metaprogramming
In 1993 compilers were beginning to support simple template constructs so that users could define generic containers and functions. About the same time that the STL was being considered for adoption into standard C++, clever and surprising examples such as the following were passed around among members of the standards committee:.
//: C05:Factorial.cpp
// Compile-time computation!
#include <iostream>
using namespace std;
template<int n>
struct Factorial {
enum {val = Factorial<n-1>::val * n};
};
template<>
struct Factorial<0> {
enum {val = 1};
};
int main() {
cout << Factorial<12>::val << endl; // 479001600
} ///:~
That this program prints the correct value of 12! is not alarming. What is alarming is that the computation is complete before the program even runs!.
When the compiler attempts to instantiate Factorial<12>, it finds it must also instantiate Factorial<11>, which requires Factorial<10>, and so on. Eventually the recursion ends with the specialization Factorial<1>, and the computation unwinds. Eventually, Factorial<12>::val is replaced by the integral constant 479001600, and compilation ends. Since all the computation is done by the compiler, the values involved must be compile-time constants, hence the use of enum.[66] When the program runs, the only work left to do is print that constant followed by a newline. To convince yourself that a specialization of Factorial results in the correct compile-time value, you could use it as an array dimension, such as:.
double nums[Factorial<5>::val];
assert(sizeof nums == sizeof(double)*120);
Compile-time programming
So what was meant to be a convenient way to perform type parameter substitution turned out to be a mechanism to support compile-time programming. Such a program is called a template metaprogram (since you’re in effect "programming a program"), and it turns out that you can do quite a lot with such a beast. In fact, template metaprogramming is Turing complete because it supports selection (if-else) and looping (through recursion); so theoretically you can perform any computation with it.[67] The factorial example above shows how to implement repetition; write a recursive template and provide a stopping criterion via a specialization. The following example shows how to compute Fibonacci numbers at compile time by the same technique.