5.10. Sequence DerivationTypically, the unnumbered form of any sequence is derived from the corresponding numbered form, or else shares with it a common base class that provides the sequence's implementation. For example, mpl::vector might be defined this way:
namespace boost { namespace mpl {
struct void_; // "no argument" marker
// primary template declaration
template <class T0 = void_, class T1 = void_, etc....>
struct vector;
// specializations
template<>
struct vector<> : vector0<> {};
template<class T0>
struct vector<T0> : vector1<T0> {};
template<class T0, class T1>
struct vector<T0,T1> : vector2<T0,T1> {};
template<class T0, class T1, class T2>
struct vector<T0,T1,T2> : vector3<T0,T1,T2> {};
etc.
}}
The integral sequence wrappers are similarly derived from equivalent underlying type sequences. All of the built-in MPL sequences are designed so that nearly any subclass functions as an equivalent type sequence. Derivation is a powerful way to provide a new interface, or just a new name, to an existing family of sequences. For example, the Boost Python library provides the following type sequence:
namespace boost { namespace python {
template <class T0=mpl::void_, ... class T4=mpl::void_>
struct bases : mpl::vector<T0, T1, T2, T3, T4> {};
}}
You can use the same technique to create a plain class that is an MPL type sequence:
struct signed_integers
: mpl::vector<signed char, short, int, long> {};
On some compilers, using signed_integers instead of the underlying vector can dramatically improve metaprogram efficiency. See Appendix C for more details. |