I l@ve RuBoard |
![]() ![]() |
6.6 Constant Expressions and Default ParametersTemplate parameters are not limited only to types, although until now I've limited my discussion to them. We can also declare constant expressions as parameters. For example, our numeric sequence class hierarchy might be redefined as a template class in which the number of elements an object contains is parameterized: template <int len> class num_sequence { public: num_sequence( int beg_pos=1 ); // ... }; template <int len> class Fibonacci : public NumericSeries<len> { public: Fibonacci( int beg_pos=1 ) : num_sequence<len>( beg_pos ){} // ... }; When a Fibonacci object is created, as in Fibonacci< 16 > fib1; Fibonacci< 16 > fib2( 17 ); instances of both the Fibonacci derived class and the num_sequence base class are generated with len bound to 16. Alternatively, we might parametermize both the length and the beginning position: template < int len, int beg_pos > class NumericSeries; However, because most class objects begin their range with position 1, this is convenient only if we provide a default value for the position: template <int len, int beg_pos> class num_sequence { ... }; template <int len, int beg_pos=1> class Fibonacci : public num_sequence<len,beg_pos> { ... }; Here is how objects of these classes might be defined: // expands as: // num_sequence<32,1> *pns1to32 = new Fibonacci<32,1>; num_sequence<32> *pns1to32 = new Fibonacci<32>; // overrides default expression parameter value num_sequence<32,33> *pns33to64 = new Fibonacci<32,33>; Like default function parameter values, the default parameter values are resolved positionally, from right to left. To illustrate how we might actually implement this, I've redefined our num_sequence and Fibonacci base and derived classes of Chapter 5 to use expression parameters: // the num_sequence class definition // we no longer need to store as data members // the length and beginning position template <int len, int beg_pos> class num_sequence { public: virtual ~num_sequence(){}; int elem( int pos ) const; const char* what_am_i() const; static int max_elems(){ return _max_elems; } ostream& print( ostream &os = cout ) const; protected: virtual void gen_elems( int pos ) const = 0; bool check_integrity( int pos, int size ) const; num_sequence( vector<int> *pe ) : _pelems( pe ){} static const int _max_elems = 1024; vector<int> *_pelems; }; // function template output operator definition template <int len, int beg_pos> ostream& operator<<( ostream &os, const num_sequence<len,beg_pos> &ns ) { return ns.print( os ); } // num_sequence member functions ... template <int len, int beg_pos> int num_sequence<len,beg_pos>:: elem( int pos ) const { if ( ! check_integrity( pos, _pelems->size() )) return 0; return (*_pelems)[ pos-1 ]; } template <int length, int beg_pos> const char* num_sequence<length, beg_pos>:: what_am_i() const { return typeid( *this ).name(); } template <int length, int beg_pos> bool num_sequence<length, beg_pos>:: check_integrity( int pos, int size ) const { if ( pos <= 0 || pos > max_elems() ){ cerr << "!! invalid position: " << pos << " Cannot honor request\n"; return false; } if ( pos > size ) gen_elems( pos ); return true; } template <int length, int beg_pos> ostream& num_sequence<length, beg_pos>:: print( ostream &os ) const { int elem_pos = beg_pos-1; int end_pos = elem_pos + length; if ( ! check_integrity( end_pos, _pelems->size() )) return os; os << "( " << beg_pos << " , " << length << " ) "; while ( elem_pos < end_pos ) os << (*_pelems)[ elem_pos++ ] << ' '; return os; } // ok: the Fibonacci class template with default parameter value template <int length, int beg_pos=1> class Fibonacci : public num_sequence<length, beg_pos> { public: Fibonacci() : num_sequence<length,beg_pos>( &_elems ){} protected: virtual void gen_elems( int pos ) const; static vector<int> _elems; }; // declare the static data member template for Fibonacci template <int length, int beg_pos> vector<int> Fibonacci<length,beg_pos>::_elems; // the Fibonacci class template member functions template <int length, int beg_pos> void Fibonacci<length,beg_pos>:: gen_elems( int pos ) const { if ( pos <= 0 || pos > max_elems() ) return; if ( _elems.empty() ) { _elems.push_back( 1 ); _elems.push_back( 1 ); } if ( _elems.size() < pos ) { int ix = _elems.size(); int n_2 = _elems[ ix-2 ], n_1 = _elems[ ix-1 ]; int elem; for ( ; ix < pos; ++ix ) { elem = n_2 + n_1; _elems.push_back( elem ); n_2 = n_1; n_1 = elem; } } } Here is a small program to exercise our implementation. fib1, fib2, and fib3 each represent a different instance of the Fibonacci class template. fib1 has a length of 8 and a default beginning position of 1. fib2 also has a length of 8 but a beginning position of 8. fib3 has a length of 12 and also a beginning position of 8. int main() { Fibonacci<8> fib1; Fibonacci<8,8> fib2; Fibonacci<12,8> fib3; cout << "fib1: " << fib1 << '\n' << "fib2: " << fib2 << '\n' << "fib3: " << fib3 << endl; }; When compiled and executed, this generates the following output : fib1: ( 1 , 8 ) 1 1 2 3 5 8 13 21 fib2: ( 8 , 8 ) 21 34 55 89 144 233 377 610 fib3: ( 8 , 12 ) 21 34 55 89 144 233 377 610 987 1597 2584 4181 Addresses of functions and objects at global scope are also constant expressions and so can also represent value parameters. For example, here is a numeric sequence class that takes a pointer to a function as its parameter: template <void (*pf)(int pos, vector<int> &seq)> class numeric_sequence { public: numeric_sequence( int len, int beg_pos = 1 ) { // sanity check that pf is non-null ... if ( ! pf ) // issue error message and bail out _len = len > 0 ? len : 1; _beg_pos = beg_pos > 0 ? beg_pos : 1; pf( beg_pos+len, _elems ); } // ... private: int _len; int _beg_pos; vector<int> _elems; }; In this example, pf addresses a function that generates pos elements of a particular sequence type within the vector seq. It might be used as follows: void fibonacci( int pos, vector<int> &seq ); void pell( int pos, vector<int> &seq ); // ... numeric_sequence<fibonacci> ns_fib( 12 ); numeric_sequence<pell> ns_pell( 18, 8 ); |
I l@ve RuBoard |
![]() ![]() |