Chapter 23: Advanced Template Use

Don't hesitate to send in feedback: send an e-mail if you like the C++ Annotations; if you think that important material was omitted; if you find errors or typos in the text or the code examples; or if you just feel like e-mailing. Send your e-mail to Frank B. Brokken.

Please state the document version you're referring to, as found in the title (in this document: 10.3.0) and please state chapter and paragraph name or number you're referring to.

All received mail is processed conscientiously, and received suggestions for improvements are usually processed by the time a new version of the Annotations is released. Except for the incidental case I will normally not acknowledge the receipt of suggestions for improvements. Please don't interpret this as me not appreciating your efforts.

The main purpose of templates is to provide a generic definition of classes and functions that may then be tailored to specific types.

But templates allow us to do more than that. If not for compiler implementation limitations, templates could be used to program, at compile-time, just about anything we use computers for. This remarkable feat, offered by no other current-day computer language, stems from the fact that templates allow us to do three things at compile-time:

Of course, asking the compiler to compute, e.g., prime numbers, is one thing. But it's a completely different thing to do so in an award winning way. Don't expect speed records to be broken when the compiler performs complex calculations for us. But that's all beside the point. In the end we can ask the compiler to compute virtually anything using C++'s template language, including prime numbers....

In this chapter these remarkable features of templates are discussed. Following a short overview of subtleties related to templates the main characteristics of template meta programming are introduced.

In addition to template type and template non-type parameters there is a third kind of template parameter, the template template parameter. This kind of template parameter is introduced next, laying the groundwork for the discusion of trait classes and policy classes.

This chapter ends with the discussion of several additional and interesting applications of templates: adapting compiler error messages, conversions to class types and an elaborate example discussing compile-time list processing.

Much of the inspiration for this chapter came from two highly recommended books: Andrei Alexandrescu's 2001 book Modern C++ design (Addison-Wesley) and Nicolai Josutis and David Vandevoorde's 2003 book Templates (Addison-Wesley).

23.1: Subtleties

In section 22.2.1 a special application of the keyword typename was discussed. There we learned that it is not only used to define a name for a (complex) type, but also to distinguish types defined by class templates from members defined by class templates. In this section two more applications of typename are introduced: In addition to the special applications of typename section 23.1.3 introduces some new syntax that is related to the extended use of the keyword typename: ::template, .template and ->template are used to inform the compiler that a name used inside a template is itself a class template.

23.1.1: Returning types nested under class templates

In the following example a nested class, not depending on a template parameter, is defined inside a class template. The class template member nested returns an object of this nested class. The example uses a (deprecated) in-class member implementation. The reason for this shortly becomes clear.
    template <typename T>
    class Outer
    {
        public:
            class Nested
            {};
            Nested nested() const
            {
                return Nested();
            }
    };
The above example compiles flawlessly. Inside the class Outer there is no ambiguity with respect to the meaning of nested's return type.

However, following good practices inline and template members should be implemented below their class interfaces (see section 7.9.1). So we remove the implementation from the interface and put it below the interface:

    template <typename T>
    class Outer
    {
        public:
            class Nested
            {};

            Nested nested() const;
    };

    template <typename T>
    Outer<T>::Nested Outer<T>::nested() const
    {
        return Nested();
    }
Suddenly the compiler refuses to compile the nested member, producing an error message like
error: expected constructor, destructor, or type conversion before 'Outer'.
Now that the implementation is moved out of the interface the return type (i.e., Outer<T>::Nested) refers to a type defined by Outer<T> rather than to a member of Outer<T>.

Here typename must once again be used. The general rule being: the keyword typename must be used whenever a type is referred to that is a subtype of a type that itself depends on a template type parameter. When using the inline implementation no such dependency is used as the function's return type is simply Nested. When implementing the function outside of the class interface (which should be considered `good practice') then a specification of the class defining Nested must be provided for the function's return type. So it becomes Outer<T>::Nested which clearly is a type depending on a template type parameter.

Like before, writing typename in front of Outer<T>::Nested removes the compilation error. Thus, the correct implementation of the function nested becomes:

    template <typename T>
    typename Outer<T>::Nested Outer<T>::nested() const
    {
        return Nested();
    }

23.1.2: Type resolution for base class members

Below we see two class templates. Base and Derived, Base being Derived's base class:
    #include <iostream>

    template <typename T>
    class Base
    {
        public:
            void member();
    };
    template <typename T>
    void Base<T>::member()
    {
        std::cout << "This is Base<T>::member()\n";
    }
    template <typename T>
    class Derived: public Base<T>
    {
        public:
            Derived();
    };
    template <typename T>
    Derived<T>::Derived()
    {
        member();
    }

This example won't compile, and the compiler tells us something like:

    error: there are no arguments to 'member' that depend on a template
           parameter, so a declaration of 'member' must be available
This error causes some confusion as ordinary (non-template) base classes readily make their public and protected members available to classes that are derived from them. This is no different for class templates, but only if the compiler can figure out what we mean. In the above example the compiler can't as it doesn't know for what type T the member function member must be initialized when called from Derived<T>::Derived.

To appreciate why this is true, consider the situation where we have defined a specialization:

    template <>
    Base<int>::member()
    {
        std::cout << "This is the int-specialization\n";
    }
Since the compiler, when Derived<SomeType>::Derived is called, does not know whether a specialization of member is in effect, it can't decide (when compiling Derived<T>::Derived) for what type to instantiate member. It can't decide this when compiling Derived<T>::Derived as member's call in Derived::Derived doesn't require a template type parameter.

In cases like these, where no template type parameter is available to determine which type to use, the compiler must be told that it should postpone its decision about the template type parameter to use (and therefore about the particular (here: member) function to call) until instantiation time.

This may be implemented in two ways: either by using this or by explicitly mentioning the base class, instantiated for the derived class's template type(s). When this is used the compiler is informed that we're referring to the type T for which the template was instantiated. Any confusion about which member function to use (the derived class or base class member) is resolved in favor of the derived class member. Alternatively, the base or derived class can explicitly be mentioned (using Base<T> or Derived<T>) as shown in the next example. Note that with the int template type the int specialization is used.

    #include <iostream>

    template <typename T>
    class Base
    {
        public:
            virtual void member();
    };
    template <typename T>
    void Base<T>::member()
    {
        std::cout << "This is Base<T>::member()\n";
    }
    template <>
    void Base<int>::member()
    {
        std::cout << "This is the int-specialization\n";
    }
    template <typename T>
    class Derived: public Base<T>
    {
        public:
            Derived();
            virtual void member();
    };
    template <typename T>
    void Derived<T>::member()
    {
        std::cout << "This is Derived<T>::member()\n";
    }
    template <typename T>
    Derived<T>::Derived()
    {
        this->member();         // Using `this' implies using the
                                // type for which T was instantiated
        Derived<T>::member();   // Same: calls the Derived member
        Base<T>::member();      // Same: calls the Base member
        std::cout << "Derived<T>::Derived() completed\n";
    }

    int main()
    {
        Derived<double> d;
        Derived<int> i;
    }

    /*
        Generated output:
    This is Derived<T>::member()
    This is Derived<T>::member()
    This is Base<T>::member()
    Derived<T>::Derived() completed
    This is Derived<T>::member()
    This is Derived<T>::member()
    This is the int-specialization
    Derived<T>::Derived() completed
    */

The above example also illustrates the use of virtual member templates (although virtual member templates aren't often used). In the example Base declares a virtual void member and Derived defines its overriding function member. In that case this->member() in Derived::Derived calls, due to member's virtual nature, Derived::member. The statement Base<T>::member(), however, always calls Base's member function and can be used to bypass dynamic polymorphism.

23.1.3: ::template, .template and ->template

In general, the compiler is able to determine the true nature of a name. As discussed, this is not always the case and sometimes we have to advise the compiler. The typename keyword may often be used for that purpose.

But typename cannot always come to the rescue. While parsing a source the compiler receives a series of tokens, representing meaningful units of text encountered in the program's source. A token could represent, e.g., an identifier or a number. Other tokens represent operators, like =, + or <. It is precisely the last token that may cause problems as it may have very different meanings. The correct meaning cannot always be determined from the context in which the compiler encounters <. In some situations the compiler does know that < does not represent the less than operator, as when a template parameter list follows the keyword template, e.g.,

    template <typename T, int N>
Clearly, in this case < does not represent a `less than' operator.

The special meaning of < when it is preceded by template forms the basis for the syntactic constructs discussed in this section.

Assume the following class has been defined:

    template <typename Type>
    class Outer
    {
        public:
            template <typename InType>
            class Inner
            {
                public:
                    template <typename X>
                    void nested();
            };
    };
The class template Outer defines a nested class template Inner. Inner in turn defines a template member function.

Next a class template Usage is defined, offering a member function caller expecting an object of the above Inner type. An initial setup for Usage looks like this:

    template <typename T1, typename T2>
    class Usage
    {
        public:
            void caller(Outer<T1>::Inner<T2> &obj);
       ...
    };
The compiler won't accept this as it interprets Outer<T1>::Inner as a class type. But there is no class Outer<T1>::Inner. Here the compiler generates an error like:
    error: 'class Outer<T1>::Inner' is not a type
To inform the compiler that Inner itself is a template, using the template type parameter <T2>, the ::template construction is required. It tells the compiler that the next < should not be interpreted as a `less than' token, but rather as a template type argument. So, the declaration is modified to:
    void caller(Outer<T1>::template Inner<T2> &obj);
This still doesn't get us where we want to be: after all Inner<T2> is a type, nested under a class template, depending on a template type parameter. In fact, the original Outer<T1>::Inner<T2> &obj declaration results in a series of error messages, one of them looking like this:
    error: expected type-name before '&' token
As is often the case this error message nicely indicates what should be done to get it right: add typename:
    void caller(typename Outer<T1>::template Inner<T2> &obj);

Of course, caller itself is not only just declared, it must also be implemented. Assume that its implementation should call Inner's member nested, instantiated for yet another type X. The class template Usage should therefore receive a third template type parameter, called T3. Assume it has been defined. To implement caller, we write:

    void caller(typename Outer<T1>::template Inner<T2> &obj)
    {
        obj.nested<T3>();
    }
Once again we run into a problem. In the function's body the compiler once again interprets < as `less than', seeing a logical expression having as its right-hand side a primary expression instead of a function call specifying a template type T3.

To tell the compiler that is should interpret <T3> as a type to instantiate, the template keyword must once again be used. This time it is used in the context of the member selection operator. We write .template to inform the compiler that what follows is not a `less than' operator, but rather a type specification. The function's final implementation becomes:

    void caller(typename Outer<T1>::template Inner<T2> &obj)
    {
        obj.template nested<T3>();
    }

Instead of defining value or reference parameters functions may also define pointer parameters. Had obj been defined as a pointer parameter the implementation would have had to use the ->template construction, rather than the .template construction. E.g.,

    void caller(typename Outer<T1>::template Inner<T2> *ptr)
    {
        ptr->template nested<T3>();
    }

23.2: Template Meta Programming

23.2.1: Values according to templates

In template programming values are preferably represented by enum values. Enums are preferred over, e.g., int const values since enums never require any linkage. They are pure symbolic values with no memory representation whatsoever.

Consider the situation where a programmer must use a cast, say a reinterpret_cast. A problem with a reinterpret_cast is that it is the ultimate way to turn off all compiler checks. All bets are off, and we can write extreme but absolutely pointless reinterpret_cast statements, like

    int intVar = 12;
    ostream &ostr = reinterpret_cast<ostream &>(intVar);

Wouldn't it be nice if the compiler would warn us against such oddities by generating an error message?

If that's what we'd like the compiler to do, there must be some way to distinguish madness from weirdness. Let's assume we agree on the following distinction: reinterpret casts are never acceptable if the target type represents a larger type than the expression (source) type, since that would immediately result in exceeding the amount of memory that's actually available to the target type. For this reason it's clearly silly to reinterpret_cast<double *>(&intVar), but reinterpret_cast<char *>(&intVar) could be defensible.

The intent is now to create a new kind of cast, let's call it reinterpret_to_smaller_cast. It should only be allowed to perform a reinterpret_to_smaller_cast if the target type occupies less memory than the source type (note that this exactly the opposite reasoning as used by Alexandrescu (2001), section 2.1).

To start, we construct the following template:

    template<typename Target, typename Source>
    Target &reinterpret_to_smaller_cast(Source &source)
    {
        // determine whether Target is smaller than source
        return reinterpret_cast<Target &>(source);
    }

At the comment an enum-definition is inserted defining a symbol having a suggestive name. A compile-time error results if the required condition is not met and the error message displays the name of the symbol. A division by zero is clearly not allowed, and noting that a false value represents a zero value, the condition could be:

    1 / (sizeof(Target) <= sizeof(Source));
The interesting part is that this condition doesn't result in any code at all. The enum's value is a plain value that's computed by the compiler while evaluating the expression:
    template<typename Target, typename Source>
    Target &reinterpret_to_smaller_cast(Source &source)
    {
        enum
        {
            the_Target_size_exceeds_the_Source_size =
                1 / (sizeof(Target) <= sizeof(Source))
        };
        return reinterpret_cast<Target &>(source);
    }
When reinterpret_to_smaller_cast is used to cast from int to double an error is produced by the compiler, like this:
    error: enumerator value for 'the_Target_size_exceeds_the_Source_size'
        is not an integer constant
whereas no error is reported if, e.g., reinterpret_to_smaller_cast<int>(doubleVar) is requested with doubleVar defined as a double.

In the above example an enum was used to compute (at compile-time) a value that is illegal if an assumption is not met. The creative part is finding an appropriate expression.

Enum values are well suited for these situations as they do not consume any memory and their evaluation does not produce any executable code. They can be used to accumulate values too: the resulting enum value then contains a final value, computed by the compiler rather than by executable code as the next sections illustrate. In general, programs shouldn't do run-time what they can do at compile-time and performing complex calculations resulting in constant values is a clear example of this principle.

23.2.1.1: Converting integral types to types

Another use of values buried inside templates is to `templatize' simple scalar int values. This is useful in situations where a scalar value (often a bool value) is available to select a specialization but a type is required to base the selection on. This situation is shortly encountered (section 23.2.2).

Templatizing integral values is based on the fact that a class template together with its template arguments defines a type. E.g., vector<int> and vector<double> are different types.

Turning integral values into templates is easily done. Define a template (it does not have to have any contents at all) and store the integral value in an enum:

    template <int x>
    struct IntType
    {
        enum { value = x };
    };
As IntType does not have any members the `class IntType' can be defined as `struct IntType', saving us from having to type public:.

Defining the enum value `value' allows us to retrieve the value used at the instantiation at no cost in storage. Enum values are neither variables nor data members and thus have no address. They are mere values.

It's easy to use the struct IntType. An anonymous or named object can be defined by specifying a value for its int non-type parameter. Example:

    int main()
    {
        IntType<1> it;
        cout << "IntType<1> objects have value: " << it.value << "\n" <<
                "IntType<2> objects are of a different type "
                        "and have values " << IntType<2>().value << '\n';
    }
Actually, neither the named object nor the anonymous object is required. As the enum is defined as a plain value, associated with the struct IntType we merely have to specify the specific int for which the struct IntType is defined to retrieve its `value', like this:
    int main()
    {
        cout << "IntType<100>, no object, defines `value': " <<
                IntType<100>::value << "\n";
    }

23.2.2: Selecting alternatives using templates

An essential characteristic of programming languages is that they allow the conditional execution of code. For this C++ offers the if and switch statements. If we want to be able to `program the compiler' this feature must also be offered by templates.

Like templates storing values templates making choices do not require any code to be executed at run-time. The selection is purely made by the compiler, at compile-time. The essence of template meta programming is that we are not using or relying on any executable code. The result of a template meta program often is executable code, but that code is a function of decisions merely made by the compiler.

Template (member) functions are only instantiated when they are actually used. Consequently we can define specializations of functions that are mutually exclusive. Thus it is possible to define a specialization that can be compiled in situation one, but not in situation two and to define another specialization that can be compiled in situation two, but not in situation one. Using specializations code can be generated that is tailored to the demands of a particular situation.

A feature like this cannot be implemented in run-time executable code. For example, when designing a generic storage class the software engineer may intend to store value class type objects as well as objects of polymorphic class types in the final storage class. Thus the software engineer may conclude that the storage class should contain pointers to objects, rather than the objects themselves. The initial implementation attempt could look like this:

    template <typename Type>
    void Storage::add(Type const &obj)
    {
        d_data.push_back(
            d_ispolymorphic ?
                obj.clone()
            :
                new Type(obj)
        );
    }
The intent is to use the clone member function of the class Type if Type is a polymorphic class and the standard copy constructor if Type is a value class.

Unfortunately, this scheme usually fails as value classes do not define clone member functions and polymorphic base classes should delete their copy constructors (cf. section 7.6). It doesn't matter to the compiler that clone is never called for value classes and that the copy constructor is only available in value classes and not in polymorphic classes. It merely has some code to compile, and can't do that because of missing members. It's as simple as that.

23.2.2.1: Defining overloading members

Template meta programming comes to the rescue. Knowing that class template member functions are only instantiated when used, our plan is to design overloaded add member functions of which only one is going to be called (and thus instantiated). Our selection will be based on an additional (in addition to Type itself) template non-type parameter that indicates whether we'll use Storage for polymorphic or non-polymorphic classes. Our class Storage starts like this:
    template <typename Type, bool isPolymorphic>
    class Storage
Initially two overloaded versions of our add member are defined: one used with Storage objects storing polymorphic objects (using true as its template non-type argument) and one storing value class objects (using false as its template non-type argument).

Unfortunately we run into a small problem: functions cannot be overloaded by their argument values but only by their argument types. But the small problem may be solved. Realizing that types are defined by the combination of template names and their template arguments we may convert the values true and false into types using the knowledge from section 23.2.1.1 about how to convert integral values to types.

We'll provide one (private) add member with a IntType<true> parameter (implementing the polymorphic class) and another (private) add member with a IntType<false> parameter (implementing the non-polymorphic class).

In addition to these two private members a third (public) member add is defined calling the appropriate private add member by providing an IntType argument, constructed from Storage's template non-type parameter.

Here are the implementations of the three add members:

    // declared in Storage's private section:

    template <typename Type, bool isPolymorphic>
    void Storage<Type, isPolymorphic>::add(Type const &obj, IntType<true>)
    {
        d_data.push_back(obj.clone());
    }

    template <typename Type, bool isPolymorphic>
    void Storage<Type, isPolymorphic>::add(Type const &obj, IntType<false>)
    {
        d_data.push_back(new Type(obj));
    }

    // declared in Storage's public section:

    template <typename Type, bool isPolymorphic>
    void Storage<Type, isPolymorphic>::add(Type const &obj)
    {
        add(obj, IntType<isPolymorphic>());
    }
The appropriate add member is instantiated and called because a primitive value can be converted to a type. Each of the possible template non-type values is thus used to define an overloaded class template member function.

Since class template members are only instantiated when used only one of the overloaded private add members is instantiated. Since the other one is never called (and thus never instantiated) compilation errors are prevented.

23.2.2.2: Class structure as a function of template parameters

Some software engineers have reservations when thinking about the Storage class that uses pointers to store copies of value class objects. Their argument is that value class objects can very well be stored by value, rather than by pointer. They'd rather store value class objects by value and polymorphic class objects by pointer.

Such distinctions frequently occur in template meta programming and the following struct IfElse may be used to obtain one of two types, depending on a bool selector value.

First define the generic form of the template:

    template<bool selector, typename FirstType, typename SecondType>
    struct IfElse
    {
        typedef FirstType type;
    };
Then define a partial specialization. The specialization represents a specific selector value (e.g., false) and leaves the remaining types open to further specification:
    template<typename FirstType, typename SecondType>
    struct IfElse<false, FirstType, SecondType>
    {
        typedef SecondType type;
    };
The former (generic) definition associates FirstType with the IfElse::type type definition, the latter definition (partially specialized for the logical value false) associates SecondType with the IfElse::type type definition.

The IfElse template allows us to define class templates whose data organization is conditional to the template's parameters. Using IfElse the Storage class may define pointers to store copies of polymorphic class type objects and values to store value class type objects:

    template <typename Type, bool isPolymorphic>
    class Storage
    {
        typedef typename IfElse<isPolymorphic, Type *, Type>::type
                DataType;

        std::vector<DataType> d_data;

        private:
            void add(Type const &obj, IntType<true>);
            void add(Type const &obj, IntType<false>);
        public:
            void add(Type const &obj);
    }

    template <typename Type, bool isPolymorphic>
    void Storage<Type, isPolymorphic>::add(Type const &obj, IntType<true>)
    {
        d_data.push_back(obj.clone());
    }

    template <typename Type, bool isPolymorphic>
    void Storage<Type, isPolymorphic>::add(Type const &obj, IntType<false>)
    {
        d_data.push_back(obj);
    }

    template <typename Type, bool isPolymorphic>
    void Storage<Type, isPolymorphic>::add(Type const &obj)
    {
        add(obj, IntType<isPolymorphic>());
    }
The above example uses IfElse's type, defined by IfElse as either FirstType or SecondType. IfElse's type defines the actual data type to use for Storage's vector data type.

The remarkable result in this example is that the data organization of the Storage class now depends on its template arguments. Since the isPolymorphic == true situation uses different data types than the isPolymorphic == false situation, the overloaded private add members can utilize this difference immediately. E.g., add(Type const &obj, IntType<false>) uses direct copy construction to store a copy of obj in d_vector.

It is also possible to make a selection from multiple types as IfElse structs can be nested. Realize that using IfElse never has any effect on the size or execution time of the final executable program. The final program simply contains the appropriate type, conditional to the type that's eventually selected.

23.2.2.3: An illustrative example

The next example, defining MapType as a map having plain types or pointers for either its key or value types, illustrates this approach:
    template <typename Key, typename Value, int selector>
    class Storage
    {
        typedef typename IfElse<
                    selector == 1,              // if selector == 1:
                    map<Key, Value>,            // use map<Key, Value>

                    typename IfElse<
                        selector == 2,          // if selector == 2:
                        map<Key, Value *>,      // use map<Key, Value *>

                        typename IfElse<
                            selector == 3,      // if selector == 3:
                            map<Key *, Value>,  // use map<Key *, Value>
                                                // otherwise:
                            map<Key *, Value *> // use map<Key *, Value *>

                        >::type
                    >::type
                >::type
                MapType;

        MapType d_map;

        public:
            void add(Key const &key, Value const &value);
        private:
            void add(Key const &key, Value const &value, IntType<1>);
           ...
    };
    template <typename Key, typename Value, int selector>
    inline void Storage<selector, Key, Value>::add(Key const &key,
                                                   Value const &value)
    {
        add(key, value, IntType<selector>());
    }
The principle used in the above examples is: if class templates may use data types that depend on template non-type parameters, an IfElse struct can be used to select the appropriate data types. Knowledge about the various data types may also be used to define overloaded member functions. The implementations of these overloaded members may then be optimized to the various data types. In programs only one of these alternate functions (the one that is optimized to the actually used data types) will then be instantiated.

The private add functions define the same parameters as the public add wrapper function, but add a specific IntType type, allowing the compiler to select the appropriate overloaded version based on the template's non-type selector parameter.

23.2.3: Templates: Iterations by Recursion

As there are no variables in template meta programming, there is no template equivalent to a for or while statement. However, iterations can always be rewritten as recursions. Recursions are supported by templates and so iterations can always be implemented as (tail) recursions.

To implement iterations by (tail) recursion do as follows:

The compiler selects a more specialized template implementation over a more generic one. By the time the compiler reaches the end-condition the recursion stops since the specialization does not use recursion.

Most readers are probably familiar with the recursive implementation of the mathematical `factorial' operator, commonly represented by the exclamation mark (!). Factorial n (so: n!) returns the successive products n * (n - 1) * (n - 2) * ... * 1, representing the number of ways n objects can be permuted. Interestingly, the factorial operator is itself usually defined by a recursive definition:

    n! = (n == 0) ?
            1
        :
            n * (n - 1)!
To compute n! from a template, a template Factorial can be defined using an int n template non-type parameter. A specialization is defined for the case n == 0. The generic implementation uses recursion according to the factorial definition. Furthermore, the Factorial template defines an enum value `value' containing its factorial value. Here is the generic definition:
    template <int n>
    struct Factorial
    {
        enum { value = n * Factorial<n - 1>::value };
    };
Note how the expression assigning a value to `value' uses constant values that can be determined by the compiler. The value n is provided, and Factorial<n - 1> is computed using template meta programming. Factorial<n-1> in turn results in value that can be determined by the compiler (viz. Factorial<n-1>::value). Factorial<n-1>::value represents the value defined by the type Factorial<n - 1>. It is not the value returned by an object of that type. There are no objects here but merely values defined by types.

The recursion ends in a specialization. The compiler selects the specialization (provided for the terminating value 0) instead of the generic implementation whenever possible. Here is the specialization's implementation:

    template <>
    struct Factorial<0>
    {
        enum { value = 1 };
    };
The Factorial template can be used to determine, compile time, the number of permutations of a fixed number of objects. E.g.,
    int main()
    {
        cout << "The number of permutations of 5 objects = " <<
                Factorial<5>::value << "\n";
    }
Once again, Factorial<5>::value is not evaluated at run-time, but at compile-time. The run-time equivalent of the above cout statement is, therefore:
    int main()
    {
        cout << "The number of permutations of 5 objects = " <<
                120 << "\n";
    }

23.3: User-defined literals

In addition to the literal operators discussed in section 11.12 C++ also offers a function template literal operator, matching the prototype
    template <char ...Chars>
    Type operator "" _identifier()
This variadic non-type parameter function template defines no parameters, but merely a variadic non-type parameter list.

Its argument must be an int constant, as is also expected by the literal operator defining an unsigned long long int parameter. All the characters of the int constant are passed as individual char non-type template arguments to the literal operator.

For example, if _NM2km is a literal operator function template, it can be called as 80_NM2km. The function template is then actually called as _NM2km<'8', '0'>(). If this function template merely uses template meta programming techniques and only processes integral data then its actions can be performed completely at compile-time. To illustrate this, let's assume NM2km only processes and returns unsigned values.

The function template _NM2km can forward its argument to a class template, defining an enum constant value, and that performs the required computations. Here is the implementation of the variadic literal operator function template _NM2km:

    template <char ... Chars>
    size_t constexpr operator "" _NM2km()
    {
        return static_cast<size_t>(             // forward Chars to NM2km
                NM2km<0, Chars ...>::value * 1.852);
    }
The class template NM2km defines three non-type parameters: acc accumulates the value, c is the first character of the variadic non-type parameters, while ...Chars represents the remaining non-type parameters, contained in a non-type parameter pack. Since c is, at each recursive call, the next character from the original non-type parameter pack, the value so far multiplied by 10 plus the value of the next character is passed as the next accumulated value to its recursive call, together with the remaining elements of the parameter pack, represented by Chars ...:
    template <size_t acc, char c, char  ...Chars>
    struct NM2km
    {
        enum
        {
            value = NM2km<10 * acc + c - '0', Chars ...>::value
        };
    };
Eventually, the parameter pack is empty. For this case a partial specialization of NM2km is available:
    template <size_t acc, char c>   // empty parameter pack
    struct NM2km<acc, c>
    {
        enum
        {
            value = 10 * acc + c - '0'
        };
    };

This works fine, but of course not in cases where binary, octal, or hexadecimal values must also be interpreted. In that case we must first determine whether the first character(s) indicate a special number system. This can be determined by the class template NM2kmBase, that is now called from the _NM2km literal operator:

    template <char ... Chars>
    size_t constexpr operator "" _NM2km()
    {
        return static_cast<size_t>(         // forward Chars to NM2kmBase
                NM2kmBase<Chars ...>::value * 1.852);
    }
The NM2kmBase class template normally assumes the decimal number system, passing base value 10 and initial sum 0 to NM2km. The NM2km class template is provided with an additional (first) non-type parameter representing the base value of the number system to use. Here is NM2kmBase:
    template <char ...Chars>
    struct NM2kmBase
    {
        enum
        {
            value = NM2km<10, 0, Chars ...>::value
        };
    };
Partial specializations handle the different number systems, by inspecting the first (one or two) characters:
    template <char ...Chars>
    struct NM2kmBase<'0', Chars ...>        // "0..."
    {
        enum
        {                                   // octal value: base 8
            value = NM2km<8, 0, Chars ...>::value
        };
    };

    template <char ...Chars>
    struct NM2kmBase<'0', 'b', Chars ...>   // "0b..."
    {
        enum
        {                                   // binary value: base 2
            value = NM2km<2, 0, Chars ...>::value
        };
    };

    template <char  ...Chars>
    struct NM2kmBase<'0', 'x', Chars ...>   // "0x..."
    {
        enum
        {                                   // hex value: base 16
            value = NM2km<16, 0, Chars ...>::value
        };
    };

NM2km is implemented as before, albeit that it can now handle various number systems. The conversion from character to numeric value is left to a small support function template, cVal:

    template <char c>
    int constexpr cVal()
    {
        return '0' <= c <= '9' ? c - '0' : 10 + c - 'a';
    }

    template <size_t base, size_t acc, char c, char  ...Chars>
    struct NM2km
    {
        enum
        {
            value = NM2km<base, base * acc + cVal<c>(),
                                        Chars ...>::value
        };
    };

    template <size_t base, size_t acc, char c>
    struct NM2km<base, acc, c>
    {
        enum { value = base * acc + cVal<c>() };
    };

23.4: Template template parameters

Consider the following situation: a software engineer is asked to design a storage class Storage. Data stored in Storage objects may either make and store copies of the data or store the data as received. Storage objects may also either use a vector or a linked list as its underlying storage medium. How should the engineer tackle this request? Should four different Storage classes be designed?

The engineer's first reaction could be to develop an all-in Storage class. It could have two data members, a list and a vector, and its constructor could be provided with maybe an enum value indicating whether the data itself or new copies should be stored. The enum value can be used to initialize a series of pointers to member functions performing the requested tasks (e.g., using a vector to store the data or a list to store copies).

Complex, but doable. Then the engineer is asked to modify the class: in the case of new copies a custom-made allocation scheme should be used rather than the standard new operator. He's also asked to allow the use of yet another type of container, in addition to the vector and the list that were already part of the design. Maybe a deque would be preferred or maybe even a stack.

It's clear that the approach aiming at implementing all functionality and all possible combinations in one class doesn't scale. The class Storage soon becomes a monolithic giant which is hard to understand, maintain, test, and deploy.

One of the reasons why the big, all-encompassing class is hard to deploy and understand is that a well-designed class should enforce constraints: the design of the class should, by itself, disallow certain operations, violations of which should be detected by the compiler, rather than by a program that might terminate in a fatal error.

Think about the above request. If the class offers both an interface to access the vector data storage and an interface to access the list data storage, then it's likely that the class offers an overloaded operator[] member to access elements in the vector. This member, however, will be syntactically present, but semantically invalid when the list data storage is selected, which doesn't support operator[].

Sooner or later, users of the monolithic all-encompassing class Storage will fall into the trap of using operator[] even though they've selected the list as the underlying data storage. The compiler won't be able to detect the error, which only appears once the program is running, confusing its users.

The question remains: how should the engineer proceed, when confronted with the above questions? It's time to introduce policies.

23.4.1: Policy classes - I

A policy defines (in some contexts: prescribes) a particular kind of behavior. In C++ a policy class defines a certain part of the class interface. It may also define inner types, member functions, and data members.

In the previous section the problem of creating a class that might use any of a series of allocation schemes was introduced. These allocation schemes all depend on the actual data type to use, and so the `template reflex' should kick in.

Allocation schemes should probably be defined as template classes, applying the appropriate allocation procedures to the data type at hand. When such allocation schemes are used by the familiar STL containers (like std::vector, std::stack, etc.), then such home-made allocation schemes should probably be derived from std::allocator, to provide for the requirements made by these containers. The class template std::allocator is declared by the <memory> header file and the three allocation schemes developed here were all derived from std::allocator.

Using in-class implementations for brevity the following allocation classes could be defined:

The above three classes define policies that may be selected by the user of the class Storage introduced in the previous section. In addition to these classes, additional allocation schemes could be implemented by the user as well.

To apply the proper allocation scheme to the class Storage, Storage should be designed as a class template itself. The class also needs a template type parameter allowing users to specify the data type.

The data type to be used by a particular allocation scheme could of course be specified when specifying the allocation scheme to use. The class Storage would then have two template type parameters, one for the data type, one for the allocation scheme:

    template <typename Data, typename Scheme>
    class Storage ...

To use the class Storage we would then write, e.g.:

    Storage<string, NewAlloc<string>> storage;
Using Storage this way is fairly complex and potentially error-prone, as it requires the user to specify the data type twice. Instead, the allocation scheme should be specified using a new type of template parameter, not requiring the user to specify the data type required by the allocation scheme. This new kind of template parameter (in addition to the well-known template type parameter and template non-type parameter) is called the template template parameter.

Starting with the C++14 standard using the keyword class in the syntactical form of template template parameters (template <parameter specifications> class Name) is no longer required. From that standard onward, the keyword typename can also be used (e.g., template <parameter specifications> typename Name).

23.4.2: Policy classes - II: template template parameters

Template template parameters allow us to specify a class template as a template parameter. By specifying a class template, it is possible to add a certain kind of behavior (called a policy) to an existing class template.

To specify an allocation policy, rather than an allocation type for the class Storage we rephrase its class template header: definition starts as follows:

    template <typename Data, template <typename> class Policy>
    class Storage...
The second template parameter is new. It is a template template parameter. It has the following elements: Policy classes are often an integral part of the class under consideration. Because of this they are often deployed as base classes. In the example the class Policy could be used as a base class of the class Storage.

The policy operates on the class Storage's data type. Therefore the policy is informed about that data type as well. Our class Storage now begins like this:

    template <typename Data, template <typename> class Policy>
    class Storage: public Policy<Data>
This automatically allows us to use Policy's members when implementing the members of the class Storage.

Our home-made allocation classes do not really provide us with many useful members. Except for the extraction operator they offer no immediate access to the data. This can easily be repaired by adding more members. E.g., the class NewAlloc could be augmented with operators allowing access to and modification of stored data:

        operator Data &()   // optionally add a `const' member too
        {
            return *d_data;
        }
        NewAlloc &operator=(Data const &data)
        {
            *d_data = data;
        }
The other allocation classes could be given comparable members.

Let's use the allocation schemes in some real code. The next example shows how Storage can be defined using some data type and an allocation scheme. We start out again with a class Storage:

    template <typename Data, template <typename> class Allocate>
    class Storage: public std::vector<Data, Allocate<Data>>
    {};
That's all we have to do. Note that std::vector formally has two template parameters. The first one is the vector's data type, which is always specified; the second one is the allocator used by the vector. Usually the allocator is left unspecified (in which case the default STL allocator is used), but here it is mentioned explicitly, allowing us to pass our own allocation policy to Storage.

All required functionality is inherited from the vector base class, while the policy is `factored into the equation' using a template template parameter. Here's an example showing how this is done:

    Storage<std::string, NewAlloc> storage;

    copy(istream_iterator<std::string>(cin), istream_iterator<std::string>(),
            back_inserter(storage));

    cout << "Element index 1 is " << storage[1] << '\n';
    storage[1] = "hello";

    copy(storage.begin(), storage.end(),
         ostream_iterator<NewAlloc<std::string> >(cout, "\n"));
Since Storage objects are also std::vector objects the STL copy function can be used in combination with the back_inserter iterator to add some data to the storage object. Its elements can be accessed and modified using the index operator. Then NewAlloc<std::string> objects are inserted into cout (also using the copy function).

Interestingly, this is not the end of the story. Remember that our intention was to create a class allowing us to specify the storage type as well. What if we don't want to use a vector, but instead would like to use a list?

It's easy to change Storage's setup so that a completely different storage type can be used on request, like a deque. To implement this, the storage class is parameterized as well, using yet another template template parameter:

    template <typename Data, template <typename> class AllocatonPolicy,
              template <typename, typename> class Container = std::vector>
    class Storage: public Container<Data, AllocationPolicy<Data>>
    {};
The earlier example using a Storage object can be used again without requiring any modifications at all (except for the above redefinition). It clearly can't be used with a list container, as the list lacks operator[]. Trying to do so is immediately recognized by the compiler, producing an error if an attempt is made to use operator[] on, e.g., a list. (A complete example showing the definition of the allocation classes and the class Storage as well as its use is provided in the Annotation's distribution in the file yo/advancedtemplates/examples/storage.cc.) A list container, however can still be specified as the container to use. In that case a Storage is implemented as a list, offering list's interface, rather than vector's interface, to its users.

23.4.2.1: The destructor of Policy classes

In the previous section policy classes were used as base classes of template classes. This resulted in the interesting observation that a policy class may serve as a base class of a derived class. As a policy class may act as a base class, a pointer or reference to such a policy class can be used to point or refer to the derived class using the policy.

This situation, although legal, should be avoided for various reasons:

To avoid these drawbacks, it is good practice to prevent the use of references or pointers to policy classes to refer or point to derived class objects. This is accomplished by providing policy classes with non-virtual protected destructors. With a non-virtual destructor there is no performance penalty and since its destructor is protected users cannot refer to classes derived from the policy class using a pointer or reference to the policy class.

23.4.3: Structure by Policy

Policy classes usually define behavior, not structure. Policy classes are normally used to parameterize some aspect of the behavior of classes that are derived from them. However, different policies may require different data members. These data members may also be defined by the policy classes. Policy classes may therefore be used to define both behavior and structure.

By providing a well-defined interface a class derived from a policy class may define member specializations using the different structures of policy classes to their advantage. For example, a plain pointer-based policy class could offer its functionality by resorting to C-style pointer juggling, whereas a vector-based policy class could use the vector's members directly.

In this example a generic class template Size could be designed expecting a container-like policy using features commonly found in containers, defining the data (and hence the structure) of the container specified in the policy. E.g.:

    template <typename Data, template <typename> class Container>
    struct Size: public Container<Data>
    {
        size_t size()
        {                           // relies on the container's `size()'
                                    // note: can't use `this->size()'
            return Container<Data>::size();
        }
    };
A specialization can now be defined for a much simpler storage class using, e.g., plain pointers (the implementation capitalizes on first and second, data members of std::pair. Cf. the example at the end of this section):
    template <typename Data>
    struct Size<Data, Plain>: public Plain<Data>
    {
        size_t size()
        {                           // relies on pointer data members
            return this->second - this->first;
        }
    };
Depending on the intentions of the template's author other members could be implemented as well.

To simplify the real use of the above templates, a generic wrapper class can be constructed: it uses the Size template matching the actually used storage type (e.g., a std::vector or some plain storage class) to define its structure:

    template <typename Data, template <typename> class Store>
    class Wrapper: public Size<Data, Store>
    {};

The above classes could now be used as follows (en passant showing an extremely basic Plain class):

    #include <iostream>
    #include <vector>

    template <typename Data>
    struct Plain: public std::pair<Data *, Data *>
    {};

    int main()
    {
        Wrapper<int, std::vector> wiv;
        std::cout << wiv.size() << "\n";

        Wrapper<int, Plain> wis;
        std::cout << wis.size() << "\n";
    }
The wiv object now defines vector-data, the wis object merely defines a std::pair object's data members.

23.5: Template aliases

In addition to function and class templates, C++ also uses templates to define an alias for a set of types. This is called a template alias. Template aliases can be specialized. The name of a template alias is a type name.

Template aliases can be used as arguments to template template parameters. This allows us to avoid the `unexpected default parameters' you may encounter when using template template parameters. E.g., defining a template specifying a template <typename> class Container is fine, but it is impossible to specify a container like vector or set as template template argument, as vector and set containers also define a second template parameter, specifying their allocation policy.

Template aliases are defined as using declarations, specifying an alias for an existing (maybe partially or fully specialized) template type. In the following example Vector is defined as an alias for vector:

    template <typename Type>
    using Vector = std::vector<Type>;

    Vector<int> vi;             // same as std::vector<int>
    std::vector<int> vi2(vi);   // copy construction: OK
So, what's the point of doing this? Looking at the vector container, we see that it defines two, rather than one, template parameters, the second parameter being the allocation policy _Alloc, by default set to std::allocator<_Tp>:
    template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
    class vector: ...
Now define a class template Generic defining a template template parameter:
    template <typename Type, template <typename> class Container>
    class Generic: public Container<Type>
    {
        ...
    };
Most likely, Generic offers members made available by the container that is actually used to create the Generic object, and adds to those some members of it own. However, a simple container like std::vector cannot be used, as std::vector doesn't match a template <typename> class Container> parameter; it requires a template <typename, typename> class Container> template template parameter.

The Vector template alias, however, is defined as a template having one template type parameter, and it uses the vector's default allocator. Consequently, passing a Vector to Generic works fine:

    Generic<int, Vector> giv;       // OK
    Generic<int, std::vector> err;  // won't compile: 2nd argument mismatch

With the aid of a small template alias it is also possible to use a completely different kind of container, like a map, with Generic:

    template <typename Type>
    using MapString = std::map<Type, std::string>;

    Generic<int, MapString> gim;    // uses map<int, string>

23.6: Trait classes

Scattered over the std namespace trait classes are found. E.g., most C++ programmers have seen the compiler mentioning `std::char_traits<char>' when performing an illegal operation on std::string objects, as in std::string s(1).

Trait classes are used to make compile-time decisions about types. Trait classes allow us to apply the proper code to the proper data type, be it a pointer, a reference, or a plain value, all this maybe in combination with const. The particular type of data to use can be inferred from the actual type that is specified (or implied) when the template is used. This can be fully automated, not requiring the template writer to make any decision.

Trait classes allow us to develop a template <typename Type1, typename Type2, ...> without the need to specify many specializations covering all combinations of, e.g., values, (const) pointers, or (const) references, which would soon result in an unmaintainable exponential explosion of template specializations (e.g., allowing these five different types for each template parameter already results in 25 combinations when two template type parameters are used: each must be covered by potentially different specializations).

Having available a trait class, the actual type can be inferred compile time, allowing the compiler to deduce whether or not the actual type is a pointer, a pointer to a member, or a const pointer, and to make comparable deductions in case the actual type is, e.g., an lvalue or rvalue reference type. This in turn allows us to write templates that define types like argument_type, first_argument_type, second_argument_type and result_type, which are required by several generic algorithms (e.g., count_if()).

A trait class usually performs no behavior. I.e., it has no constructor and no members that can be called. Instead, it defines a series of types and enum values that have certain values depending on the actual type that is passed to the trait class template. The compiler uses one of a set of available specializations to select the one appropriate for an actual template type parameter.

The point of departure when defining a trait template is a plain vanilla struct, defining the characteristics of a plain value type like an int. This sets the stage for specific specializations, modifying the characteristics for any other type that could be specified for the template.

To make matters concrete, assume the intent is to create a trait class BasicTraits telling us whether a type is a plain value type, a pointer type, an lvalue reference type or an rvalue reference type (all of which may or may not be const types).

Whatever the actually provided type, we want to be able to determine the `plain' type (i.e., the type without any modifiers, pointers or references), the `pointer type' and the `reference type', allowing us to define in all cases, e.g., an rvalue reference to its built-in type, even though we passed a const pointer to that type.

Our point of departure, as mentioned, is a plain struct defining the required parameter. Maybe something like this:

        template <typename T>
        struct Basic
        {
            typedef T Type;
            enum
            {
                isPointer = false,
                isConst = false,
                isRef = false,
                isRRef = false
            };
        };

Although some conclusions can be drawn by combining various enum values (e.g., a plain type is not a pointer or a reference or a rvalue reference or a const), it is good practice to provide a full implementation of trait classes, not requiring its users to construct these logical expressions themselves. Therefore, the basic decisions in a trait class are usually made by a nested trait class, leaving the task of creating appropriate logical expressions to a surrounding trait class.

So, the struct Basic defines the generic form of our inner trait class. Specializations handle specific details. E.g., a pointer type is recognized by the following specialization:

        template <typename T>
        struct Basic<T *>
        {
            typedef T Type;
            enum
            {
                isPointer = true,
                isConst = false,
                isRef = false,
                isRRef = false
            };
        };

whereas a pointer to a const type is matched with the next specialization:

        template <typename T>
        struct Basic<T const *>
        {
            typedef T Type;
            enum
            {
                isPointer = true,
                isConst = true,
                isRef = false,
                isRRef = false
            };
        };

Several other specializations should be defined: e.g., recognizing const value types or (rvalue) reference types. Eventually all these specializations are implemented as nested structs of an outer class BasicTraits, offering the public traits class interface. The outline of the outer trait class is:

    template <typename TypeParam>
    class BasicTraits
    {
        // Define specializations of the template `Base' here

        public:
            BasicTraits(BasicTraits const &other) = delete;

            typedef typename Basic<TypeParam>::Type ValueType;
            typedef ValueType *PtrType;
            typedef ValueType &RefType;
            typedef ValueType &&RvalueRefType;

            enum
            {
                isPointerType = Basic<TypeParam>::isPointer,
                isReferenceType = Basic<TypeParam>::isRef,
                isRvalueReferenceType = Basic<TypeParam>::isRRef,
                isConst = Basic<TypeParam>::isConst,
                isPlainType = not (isPointerType or isReferenceType or
                                   isRvalueReferenceType or isConst)
            };
    };
The trait class's public interface explicitly deletes its copy constructor. As it therefore defines no constructor at all and as it has no static members it does not offer any run-time executable code. All the trait class's facilities must therefore be used compile time.

A trait class template can be used to obtain the proper type, irrespective of the template type argument provided. It can also be used to select a proper specialization that depends on, e.g., the const-ness of a template type. Example:

     cout <<
      "int: plain type? "     << BasicTraits<int>::isPlainType << "\n"
      "int: ptr? "            << BasicTraits<int>::isPointerType << "\n"
      "int: const? "          << BasicTraits<int>::isConst << "\n"
      "int *: ptr? "          << BasicTraits<int *>::isPointerType << "\n"
      "int const *: ptr? "    << BasicTraits<int const *>::isPointerType <<
                                                                      "\n"
      "int const: const? "    << BasicTraits<int const>::isConst << "\n"
      "int: reference? "      << BasicTraits<int>::isReferenceType << "\n"
      "int &: reference? "    << BasicTraits<int &>::isReferenceType << "\n"
      "int const &: ref ? "   << BasicTraits<int const &>::isReferenceType <<
                                                                        "\n"
      "int const &: const ? " << BasicTraits<int const &>::isConst << "\n"
      "int &&: r-reference? " << BasicTraits<int &&>::isRvalueReferenceType <<
                                                                        "\n"
      "int &&: const? " << BasicTraits<int &&>::isConst << "\n"
      "int const &&: r-ref ? "<< BasicTraits<int const &&>::
                                                isRvalueReferenceType << "\n"
      "int const &&: const ? "<< BasicTraits<int const &&>::isConst << "\n"
        "\n";

     BasicTraits<int *>::ValueType           value = 12;
     BasicTraits<int const *>::RvalueRefType rvalue = int(10);
     BasicTraits<int const &&>::PtrType      ptr = new int(14);
     cout << value << ' ' << rvalue << ' ' << *ptr << '\n';

23.6.1: Distinguishing class from non-class types

In the previous section the TypeTrait trait class was developed. Using specialized versions of a nested struct Type modifiers, pointers, references and values could be distinguished.

Knowing whether a type is a class type or not (e.g., the type represents a primitive type) could also be a useful bit of knowledge to a template developer. The class template developer might want to define a specialization when the template's type parameter represents a class type (maybe using some member function that should be available) and another specialization for non-class types.

This section addresses the question how a trait class can distinguish class types from non-class types.

In order to distinguish classes from non-class types a distinguishing feature that can be used at compile-time must be found. It may take some thinking to find such a distinguishing characteristic, but a good candidate eventually is found in the pointer to members syntactic construct. Pointers to members are only available for classes. Using the pointer to member construct as the distinguishing characteristic, a specialization can be developed that uses the pointer to member if available. Another specialization (or the generic template) does something else if the pointer to member construction is not available.

How can we distinguish a pointer to a member from `a generic situation', not being a pointer to a member? Fortunately, such a distinction is possible. A function template specialization can be defined having a parameter which is a pointer to a member function. The generic function template then accepts any other argument. The compiler selects the former (specialized) function when the provided type is a class type as class types may support a pointer to a member. The interesting verb here is `may': the class does not have to define a pointer to member.

Furthermore, the compiler does not actually call any function: we're talking compile-time here. All the compiler does is to select the appropriate function by evaluating a constant expression.

So, our intended function template now looks like this:

    template <typename ClassType>
    static `some returntype'  fun(void (ClassType::*)());
The function's return type (`(some returntype)') will be defined shortly. Let's first have a closer look at the function's parameter. The function's parameter defines a pointer to a member returning void. Such a function does not have to exist for the concrete class-type that's specified when the function is used. In fact, no implementation is provided. The function fun is only declared as a static member in the trait class. It's not implemented and no trait class object is required to call it. What, then, is its use?

To answer the question we now have a look at the generic function template that should be used when the template's argument is not a class type. The language offers a `worst case' parameter in its ellipsis parameter list. The ellipsis is a final resort the compiler may turn to if everything else fails. The generic function template specifies a plain ellipsis in its parameter list:

    template <typename NonClassType>
    static `some returntype' fun(...);
It would be an error to define the generic alternative as a function expecting an int. The compiler, when confronted with alternatives, favors the simplest, most specified alternative over a more complex, generic one. So, when providing fun with an argument it selects int whenever possible and it won't select fun(void (ClassType::*)()). When given the choice between fun(void (ClassType::*)()) and fun(...) it selects the former unless it can't do that.

The question now becomes: what argument can be used for both a pointer to a member and for the ellipsis? Actually, there is such a `one size fits all' argument: 0. The value 0 can be passed as argument value to functions defining an ellipsis parameter and to functions defining a pointers-to-member parameter.

But 0 does not specify a particular class. Therefore, fun must specify an explicit template argument, appearing in our code as fun<Type>(0), with Type being the template type parameter of the trait class.

Now for the return type. The function's return type cannot be a simple value (like true or false). Our eventual intent is to provide the trait class with an enum telling us whether the trait class's template argument represents a class type or not. That enum becomes something like this:

    enum { isClass = some class/non-class distinguishing expression } ;
The distinguishing expression cannot be
    enum { isClass = fun<Type>(0) } ;
as fun<Type>(0) is not a constant expression and enum values must be defined by constant expressions so they can be determined at compile-time.

To determine isClass's value we must find an expression allowing for compile-time discriminations between fun<Type>(...) and fun<Type>(void (Type::*)()).

In situations like these the sizeof operator often is our tool of choice as it is evaluated at compile-time. By defining different sized return types for the two fun declarations we are able to distinguish (at compile-time) which of the two fun alternatives is selected by the compiler.

The char type is by definition a type having size 1. By defining another type containing two consecutive char values a larger type is obtained. A char [2] is of course not a type, but a char[2] can be defined as a data member of a struct, and a struct does define a type. That struct then has a size exceeding 1. E.g.,

    struct Char2
    {
        char data[2];
    };
Char2 can be defined as a nested type of our traits class. The two fun function template declarations become:
    template <typename ClassType>
    static Char2 fun(void (ClassType::*)());

    template <typename NonClassType>
    static char fun(...);
Since sizeof expressions are evaluated at compile-time we can now determine isClass's value:
    enum { isClass = sizeof(fun<Type>(0)) == sizeof(Char2) };
This expression has several interesting implications: Without requiring any instantiation the trait class can now provide an answer to the question whether a template type argument represents a class type or not. Marvelous!

23.6.2: Available type traits

C++ offers many facilities to identify and modifiy characteristics of types. Before using these facilities the <type_traits> header file must be included.

All facilities offered by type_traits are defined in the std namespace (omitted from the examples given below), allowing programmers to determine various characteristics of types and values.

In the description of available type traits the following concepts are encountered:

When type-condion applies to a type, it must be a complete type, void, or an array of unknown size;

The following type traits are provided:

23.7: Using `noexcept' when offering the `strong guarantee'

When throwing exceptions while trying to achieve the strong guarantee a function's actions are usually split in two parts

The actions in the first step might be made move aware by using std::move (e.g., to assign the source's values to a (possibly temporary) destination). However, using std::move can easily affect the source (e.g., when extending the source's memory, moving the existing data to its new locations), which breaks the first step's assumption, as the target object is now modified.

In this case (and generally) the move operation should not be allowed to throw exceptions. This, in turn, implies that it is difficult to write code which must offer a non-throwing moving constructor, if it uses (external) data types over which the moving constructor has no control. E.g.,

    template <typename Type>
    class MyClass
    {
        Type d_f;
        public:
            MyClass() = default;
            MyClass(MyClass &&tmp)
            :
                d_f(move(tmp.d_f))
            {}
    };
Here, MyClass's author has no control over the design of Type. If Foreign merely has a (possibly throwing) copy constructor, then the following code breaks the no-throw assumption underlying move constructors:
    MyClass<Foreign> s2(move(MyClass<Foreign>()));

If templates are able to detect whether Type has non-throwing move constructors then their implementations may be optimized by calling these move constructors (already modifying their targets in the first part of code offering the strong guarantee) in situations where otherwise the non-modifying, but more expensive copy constructor has to be used.

The noexcept keyword was introduced to allow such templates to perform such optimizations. As with throw lists, checking for noexcept is a run-time check, but the consequence of violating a noexept declaration are more serious than violating a throw list: violating noexcept results in calling std::terminate, terminating the program, possibly without unwinding the stack. In the context of the previous example, the following code is flawlessly accepted by the compiler, demonstrating that there is no compile-time checking of noexcept:

    class Foreign
    {
        public:
            Foreign() = default;
            Foreign(Foreign const &other) noexcept
            {
                throw 1;
            }
    };
However, when this class's copy constructor is called, execution aborts with the following message:
    terminate called after throwing an instance of 'int'
    Abort

Keep in mind that the current purpose of noexcept is to allow templates to optimize their code by using move operations where the code must also be able to offer the string exception guarantee. Since noexcept also offers the conditional noexcept(condition) syntax (with noexcept(true) and noexcept having identical semantics), noexcept can be made conditional to the `noexcepting' nature of template types. Note that this is not possible with throw lists.

The following rules of thumb by be used to decide whether or not to use noexcept in your code:

23.8: More conversions to class types

23.8.1: Types to types

Although class templates may be partially specialized, function templates may not. At times this is annoying. Assume a function template is available implementing a certain unary operator that could be used with the transform generic algorithm (cf. section 19.1.63):
    template <typename Return, typename Argument>
    Return chop(Argument const &arg)
    {
        return Return(arg);
    }
Furthermore assume that if Return is std::string then the above implementation should not be used. Instead, with std::string a second argument 1 should always be provided. If Argument is a C++ string, this would allow us to, e.g., return a copy of arg from which its first character has been chopped off.

Since chop is a function, it is not possible to define a partial specialization like this:

    template <typename Argument>        // This won't compile!
    std::string chop<std::string, Argument>(Argument const &arg)
    {
        return string(arg, 1);
    }
Although a function template cannot be partially specialized it is possible to use overloading, defining a second, dummy, string parameter:
    template <typename Argument>
    std::string chop(Argument const &arg, std::string)
    {
        return string(arg, 1);
    }
Now it is possible to distinguish the two cases, but at the expense of a more complex function call. Moreover, in code this function may require the use of the bind2nd binder (cf. section 18.1.4) to provide the dummy second argument, or it may require a (possibly expensive to construct) dummy argument to allow the compiler to choose among the two overloaded function templates.

Instead of providing a string dummy argument the functions could use the IntType template (cf. section 23.2.1.1) to select the proper overloaded version. E.g., IntType<0> could be defined as the type of the second argument of the first overloaded chop function, and IntType<1> could be used for the second overloaded function. From the point of view of program efficiency this is an attractive option, as the provided IntType objects are extremely lightweight. IntType objects contain no data at all. But there's also an obvious disadvantage as there is no intuitively clear association between the int value used and the intended type.

Instead of defining arbitrary IntType types it is more attractive to use another lightweight solution, using an automatic type-to-type association. The struct TypeType is a lightweight type wrapper, much like IntType. Here is its definition:

    template <typename T>
    struct TypeType
    {
        typedef T Type;
    };
TypeType is also a lightweight type as it doesn't have any data fields either. TypeType allows us to use a natural type association for chop's second argument. E.g, the overloaded functions can now be defined as follows:
    template <typename Return, typename Argument>
    Return chop(Argument const &arg, TypeType<Argument> )
    {
        return Return(arg);
    }

    template <typename Argument>
    std::string chop(Argument const &arg, TypeType<std::string> )
    {
        return std::string(arg, 1);
    }
Using the above implementations any type can be specified for Result. If it happens to be a std::string the appropriate overloaded version is automatically selected. The following additional overload of the function chop capitalizes on this:
    template <typename Result>
    Result chop(char const *txt)    // char const * could also be a 2nd
    {                               // template type parameter
        return chop(std::string(txt), TypeType<Result>());
    }
Using the third chop function, the following statement produces the text `ello world':
    cout << chop<string>("hello world") << '\n';
Template functions do not support partial specializations. But they can be overloaded. By providing overloads with dummy type-arguments that depend on other parameters and calling these overloads from a overloaded function that does not require the dummy type argument a situation similar to partial specializations with class templates can often be realized.

23.8.2: An empty type

At times (cf. section 23.9) an empty struct is a useful tool. It can be used as a type acting analogously to the final 0-byte in NTB-strings. It can simply be defined as:
    struct NullType
    {};

23.8.3: Type convertibility

In what situations can a type T be used as a `stand in' for another type U? Since C++ is a strongly typed language the answer is surprisingly simple: Ts can be used instead of Us if a T is accepted as argument in cases where Us are requested.

This reasoning is behind the following class which can be used to determine whether a type T can be used where a type U is expected. The interesting part is that no code is actually generated or executed. All decisions are made by the compiler.

In the second part of this section we'll show how the code developed in the first part can be used to detect whether a class B is a base class of another class D (the is_base_of template (cf. section 23.6.2) also provides an answer to this question). The code developed here closely follows the example provided by Alexandrescu (2001, p. 35).

First, a function test is designed accepting a type U. The function test returns a value of the as yet unknown type Convertible:

    Convertible test(U const &);

The function test is never implemented. It is only declared. If a type T can be used instead of a type U then T can also be passed as argument to the above test function.

On the other hand, if the alternate type T cannot be used where a U is expected, then the compiler won't be able to use the above test function. Instead, it uses an alternative function that has a lower selection priority but that can always be used with any T type.

C (and C++) offer a very general parameter list, a parameter list that is always considered acceptable. This parameter list is the familiar ellipsis which represents the worst case the compiler may encounter. If everything else fails, then the function defining an ellipsis as its parameter list is selected.

Usually that's not a productive alternative, but in the current situation it is exactly what is needed. When confronted with two candidate functions, one of which defines an ellipsis parameter, the compiler selects the function defining the ellipsis parameter only if the alternative(s) can't be used.

Following the above reasoning an alternative function test(...) is declared as well. This alternate function does not return a Convertible value but a NotConvertible value:

    NotConvertible test(...);

If test's argument is of type T and if T can be converted to U then test's return type is Convertible. Otherwise NotConvertible is returned.

This situation clearly shows similarities with the situation encountered in section 23.6.1 where the value isClass had to be determined compile time. Here two related problems must be solved:

The first problem is solved by realizing that no T needs to be defined. After all, the intent is to decide compile-time whether a type is convertible and not to define a T value or object. Defining objects is not a compile-time but a run-time matter.

By simply declaring a function returning a T we can tell the compiler where it should assume a T:

    T makeT();
This mysterious function has the magical power of enticing the compiler into thinking that a T object comes out of it. However, this function needs a small modification before it will actually suit our needs. If, for whatever reason, T happens to be an array then the compiler will choke on T makeT() as functions cannot return arrays. This, however, is easily solved, as functions can return references to arrays. So the above declaration is changed into:
    T const &makeT();

Next we pass a T const & to test: following code:

    test(makeT())
Now that the compiler sees test being called with a T const & argument it decides that its return value is Convertible if a conversion is in fact possible. Otherwise it decides that its return value is NotConvertible (as the compiler, in that case, selected test(...)).

The second problem, distinguishing Convertible from NotConvertible is solved exactly the way isClass could be determined in section 23.6.1, viz. by making their sizes different. Having done so the following expression determines whether T is convertible from U or not:

    isConvertible = sizeof(test(makeT())) == sizeof(Convertible);
By using char for Convertible and Char2 (cf. section 23.6.1) for NotConvertible the distinction can be made.

The above can be summarized in a class template LconvertibleToR, having two template type parameters:

    template <typename T, typename U>
    class LconvertibleToR
    {
        struct Char2
        {
            char array[2];
        };
        static T const &makeT();
        static char test(U const &);
        static Char2 test(...);

        public:
            LconvertibleToR(LconvertibleToR const &other) = delete;
            enum { yes = sizeof(test(makeT())) == sizeof(char) };
            enum { sameType = 0 };
    };

    template <typename T>
    class LconvertibleToR<T, T>
    {
        public:
            LconvertibleToR(LconvertibleToR const &other) = delete;
            enum { yes = 1 };
            enum { sameType = 1 };
    };

As the class template deletes its copy constructor no object can be created. Only its enum values can be interrogated. The next example writes 1 0 1 0 when run from a main function:

    cout <<
        LconvertibleToR<ofstream, ostream>::yes << " " <<
        LconvertibleToR<ostream, ofstream>::yes << " " <<
        LconvertibleToR<int, double>::yes << " " <<
        LconvertibleToR<int, string>::yes <<
        "\n";

23.8.3.1: Determining inheritance

Now that it is possible to determine type convertibility, it's easy to determine whether a type Base is a (public) base class of a type Derived.

Inheritance is determined by inspecting convertibility of (const) pointers. Derived const * can be converted to Base const * if

Assuming the last conversion isn't used inheritance can be determined using the following trait class LBaseRDerived. LBaseRDerived provides an enum yes which is 1 if the left type is a base class of the right type and both types are different:
    template <typename Base, typename Derived>
    struct LBaseRDerived
    {
        LBaseRDerived(LBaseRDerived const &) = delete;
        enum {
            yes =
                LconvertibleToR<Derived const *, Base const *>::yes &&
                not LconvertibleToR<Base const *, void const *>::sameType
        };
    };

If code should not consider a class to be its own base class, then the trait class LBaseRtrulyDerived can be used to perform a strict test. This trait class adds a test for type-equality:

    template <typename Base, typename Derived>
    struct LBaseRtrulyDerived
    {
        LBaseRtrulyDerived(LBaseRtrulyDerived const &) = delete;
        enum {
            yes =
                LBaseRDerived<Base, Derived>::yes &&
                not LconvertibleToR<Base const *, Derived const *>::sameType
        };
    };

Example: the next statement displays 1: 0, 2: 1, 3: 0, 4: 1, 5: 0 when executed from a main function:

    cout << "\n" <<
        "1: " << LBaseRDerived<ofstream, ostream>::yes << ",  " <<
        "2: " << LBaseRDerived<ostream, ofstream>::yes << ",  " <<
        "3: " << LBaseRDerived<void, ofstream>::yes << ",  " <<
        "4: " << LBaseRDerived<ostream, ostream>::yes << ",  " <<
        "5: " << LBaseRtrulyDerived<ostream, ostream>::yes <<
        "\n";

23.9: Template TypeList processing

This section serves two purposes. It illustrates capabilities of the various template meta-programming techniques, which can be used as a source of inspiration when developing your own templates; and it offers a concrete example, illustrating some of the power offered by these techniques.

This section itself was inspired by Andrei Alexandrescu's (2001) book Modern C++ design. It diverts from Alexandrescu's book in its use of variadic templates which were not yet available when he wrote his book. Even so, the algorithms used by Alexandrescu are still useful when using variadic templates.

C++ offers the tuple to store and retrieve values of multiple types. Here the focus is merely on processing types. A simple struct TypeList is going to be used as our working horse for the upcoming subsections. Here is its definition:

    template <typename ...Types>
    struct TypeList
    {
        TypeList(TypeList const &) = delete;
        enum { size = sizeof ...(Types) };
    };

A typelist allows us to store any number of types. Here is an example storing the three types char, short, int in a TypeList:

    TypeList<char, short, int>

23.9.1: The length of a TypeList

As the number of types in a parameter pack may be obtained using the sizeof operator (cf. section 22.5) it is easy to obtain the number of types that were specified with a certain TypeList. For example, the following statement displays the value 3:
    std::cout << TypeList<int, char, bool>::size << '\n';

However, it's illustrative to see how the number of types specified with a TypeList could be determined if sizeof hadn't been available.

To obtain the number of types that were specified with a TypeList the following algorithm is used:

The algorithm uses recursion to define the length of a TypeList. In executable C++ recursion could also be used in comparable situations. For example recursion can be used to determine the length of an NTBS:
    size_t c_length(char const *cp)
    {
        return *cp == 0 ? 0 : 1 + c_length(cp + 1);
    }
While C++ functions usually use iteration rather than recursion, iteration is not available to template meta programming algorithms. In template meta programming repetition must be implemented using recursion. Furthermore, while C++ run-time code may use conditions to decide whether or not to start the next recursion template meta programming cannot do so. Template meta programming algorithms must resort to (partial) specializations. The specializations are used to select alternatives.

The number of types that are specified in a TypeList can be computed using the following alternate implementation of TypeList, using a generic struct declaration and two specialization for the empty and non-empty TypeList (cf. the above description of the algorithm):

    template <typename ...Types>
    struct TypeList;

    template <typename Head, typename ...Tail>
    struct TypeList
    {
        enum { size = 1 + TypeList<Tail...>::size };
    };
    template <>
    struct TypeList<>
    {
        enum { size = 0 };
    };

23.9.2: Searching a TypeList

To determine whether a particular type (called SearchType below) is present in a given TypeList, an algorithm is used that either defines `index' as -1 (if SearchType is not an element of the TypeList ) or it defines `index' as the index of the first occurrence of SearchType in the TypeList. The following algorithm is used: The algorithm is implemented using a variadic template struct ListSearch expecting a parameter pack:
    template <typename ...Types>
    struct ListSearch
    {
        ListSearch(ListSearch const &) = delete;
    };

Specializations handle the alternatives mentioned with the algorithm:

Here is an example showing how ListSearch can be used:
    std::cout <<
        ListSearch<char, TypeList<int, char, bool>>::index << "\n" <<
        ListSearch<float, TypeList<int, char, bool>>::index << "\n";

23.9.3: Selecting from a TypeList

The inverse operation of determining the index of a certain type in a TypeList is retrieving the type given its index. This inverse operation is the topic of this section.

The algorithm is implemented using a struct TypeAt. TypeAt uses a typedef to define the type matching a given index. But the index might be out of bounds. In that case we have several options:

The first alternative is implemented below. The other alternatives are not difficult to implement and are left as exercises for the reader. Here's how TypeAt works: Here is how typeAt can be used. Uncommenting the first variable definition causes a TypeAt index out of bounds compilation error:
    typedef TypeList<int, char, bool> list3;

//    TypeAt<3, list3>::Type invalid;
    TypeAt<0, list3>::Type intVariable = 13;
    TypeAt<2, list3>::Type boolVariable = true;

    cout << "The size of the first type is " <<
                sizeof(TypeAt<0, list3>::Type) << ", "
            "the size of the third type is " <<
                sizeof(TypeAt<2, list3>::Type) << "\n";

    if (typeid(TypeAt<1, list3>::Type) == typeid(char))
        cout << "The typelist's 2nd type is char\n";

    if (typeid(TypeAt<2, list3>::Type) != typeid(char))
        cout << "The typelist's 3nd type is not char\n";

23.9.4: Prefixing/Appending to a TypeList

Prepending or appending a type to a TypeList is easy and doesn't require recursive template meta programs. Two variadic template structs Append and Prefix and two specializations are all it takes.

Here are the declarations of the two variadic template structs:

    template <typename ...Types>
    struct Append;

    template <typename ...Types>
    struct Prefix;

To append or prefix a new type to a typelist, specializations expect a typelist and a type to add. Then, they simply define a new TypeList also including the new type. The Append specialization shows that a template pack does not have to be used as the first argument when defining another variadic template type:

    template <typename NewType, typename ...Types>
    struct Append<TypeList<Types...>, NewType>
    {
        typedef TypeList<Types..., NewType> List;
    };

    template <typename NewType, typename ...Types>
    struct Prefix<NewType, TypeList<Types...>>
    {
        typedef TypeList<NewType, Types...> List;
    };

23.9.5: Erasing from a TypeList

It is also possible to erase types from a TypeList. Again, there are several possibilities, each resulting in a different algorithm. Doubtlessly there are other ways of erasing types from a TypeList. Which ones are eventually implemented depends of course on the circumstances. As template meta programming is very powerful most if not all algorithms can probably be implemented. As an illustration of how to erase types from a TypeList the above-mentioned algorithms are now developed in the upcoming subsections.

23.9.5.1: Erasing the first occurrence

To erase the first occurrence of a specified EraseType from a TypeList a recursive algorithm is used once again. The template meta program uses a generic Erase struct and several specializations. The specializations define a type List containing the resulting TypeList after the erasure. Here is the algorithm: Here is a statement showing how Erase can be used:
    cout <<
            Erase<int, TypeList<char, double, int>>::List::size << '\n' <<
            Erase<char, TypeList<int>>::List::size << '\n' <<
            Erase<int, TypeList<int>>::List::size << '\n' <<
            Erase<int, TypeList<>>::List::size << "\n";

23.9.5.2: Erasing a type by its index

To erase a type from a TypeList by its index we again use a recursive template meta program. EraseIdx expects a size_t index value and a TypeList from which its idxth (0-based) type must be erased. EraseIdx defines the type List containing the resulting TypeList. Here is the algorithm: Here is a statement showing how EraseIdx can be used:
    if
    (
        typeid(TypeAt<2,
                EraseIdx<1,
                   TypeList<int, char, size_t, double, int>>::List
                >::Type
        )
        == typeid(double)
    )
        cout << "the third type is now a double\n";

23.9.5.3: Erasing all occurrences of a type

Erasing all types EraseType from a TypeList can easily be accomplished by applying the erasure procedure not only to the head of the TypeList but also to the TypeList's tail.

Here is the algorithm, described in a slightly different order than Erase's algorithm:

Here is a statement showing how EraseAll can be used:
    cout <<
        "After erasing size_t from "
            "TypeList<char, int, size_t, double, size_t>\n"
            "it contains " <<
                EraseAll<size_t,
                         TypeList<char, int, size_t, double, size_t>
                >::List::size << " types\n";

23.9.5.4: Erasing duplicates

To remove all duplicates from a TypeList all the TypeList's first elements must be erased from the TypeList's tail, applying the procedure recursively to the TypeList's tail. The algorithm, outlined below, merely expects a TypeList: Here is an example showing how EraseDup can be used:
    cout <<
        "After erasing duplicates from "
             "TypeList<double, char, int, size_t, int, double, size_t>\n"
        "it contains " <<
        EraseDup<
            TypeList<double, char, int, size_t, int, double, size_t>
        >::List::size << " types\n";

23.10: Using a TypeList

In the previous sections the definition and some of the features of typelists were discussed. Most C++ programmers consider typelists both exciting and an intellectual challenge, honing their skills in the area of recursive programming.

But there's more to typelist than a mere intellectual challenge. In the final sections of this chapter the following topics are covered:

Again, much of the material covered by these sections was inspired by Alexandrescu's (2001) book.

23.10.1: The Wrap and Multi class templates

To illustrate template meta programming concepts the template class Multi is now developed. The class template Multi creates a new class from a template template parameter Policy defining the data storage policy and a series of types from which Multi is eventually derived. It does so by passing its template parameters to its base class MultiBase that in turn creates a final class inheritance tree. Since we don't know how many types are going to be used Multi is defined as a variadic class template using a template pack ...Types.

In fact, the types that are specified with Multi aren't that interesting. They primarily serve to `seed' the class Policy. Therefore, rather than forwarding Multi's types to MultiBase they are passed to Policy and the sequence of Policy<Type> types is then forwarded to MultiBase. Multi's constructor expects initialization values for its various Policy<Type>s which are perfectly forwarded to MultiBase.

The class Multi (implementing its constructor in-class to save some space) shows how a template pack can be wrapped into a policy. Here is Multi's definition:

    template <template <typename> class Policy, typename ...Types>
    struct Multi: public MultiBase<0, Policy<Types>...>
    {
        typedef TypeList<Types...> PlainTypes;
        typedef MultiBase<0, Policy<Types>...> Base;

        enum { size = PlainTypes::size };

        Multi(Policy<Types> &&...types)
        :
            MultiBase<0, Policy<Types>...>(
                            std::forward<Policy<Types>>(types)...)
        {}
    };

Unfortunately, the design as described contains some flaws.

There is a way around the problem of duplicate base class types. If instead of inheriting directly from base classes these base classes are first wrapped in unique type defining classes, then these unique classes can be used to access the base classes using principles of inheritance. As these unique type-defining wrapper classes are merely classes that are derived from the `real' base classes they inherit (and thus: offer) the functionality of their base classes. A unique type defining wrapper class can be designed after the class IntType, defined earlier. The wrapper class we're looking combines class derivation with the uniqueness offered by IntType. The class template UWrap has two template parameters: one non-type parameter idx and one type parameter. By ensuring that each UWrap definition uses a unique idx value unique class types are created. These unique class types are then used as base classes of the derived class MultiBase:
    template <size_t nr, typename Type>
    struct UWrap: public Type
    {
        UWrap(Type const &type)
        :
            Type(type)
        {}
    };

Using UWrap it's easy to distinguish, e.g., two vector<int> classes: UWrap<0, vector<int>> could refer to the first vector<int>, UWrap<1, vector<int>> to the second vector.

Uniqueness of the various UWrap types is assured by the class template MultiBase as discussed in the next section.

It must also be possible to initialize a Multi class object. Its constructor therefore expects the initialization values for all its Policy values. So if a Multi is defined for Vector, int, string then its constructor can receive the matching initialization values. E.g.,

    Multi<Vector, int, string> mvis({1, 2, 3}, {"one", "two", "three"});

23.10.2: The MultiBase class template

The class template MultiBase is Multi's base class. It defines a class that, eventually, is derived from the list of Policy types that, in turn, were created by Multi using any additional types that were passed to it.

MultiBase itself has no concept of a Policy. To MultiBase the world appears to consist of a simple template pack whose types are used to define a class from. In addition to the PolicyTypes template pack, MultiBase also defines a size_t nr non-type parameter that is used to create unique UWrap types. Here is MultiBase's generic class declaration:

    template <size_t nr, typename ...PolicyTypes>
    struct MultiBase;

Two specializations handle all possible MultiBase invocations. One specialization is a recursive template. This template handles the first type of MultiBase's template parameter pack and recursively uses itself to handle the remaining types. The second specialization is invoked once the template parameter pack is exhausted and does nothing. Here is the definition of the latter specialization:

    template <size_t nr>
    struct MultiBase<nr>
    {};

The recursively defined specialization is the interesting one. It performs the following tasks:

An illustration showing the layout of the MultiBase class hierarchy is provided in figure 27.

Figure 27 is shown here.
Figure 27: Layout of a MultiBase class hierarchy

MultiBase's constructor simply receives the initialization values that were (originally) passed to the Multi object. Perfect forwarding is used to accomplish this. MultiBase's constructor passes its first parameter value to its UWrap base class, also using perfect forwarding. MultiBase's recursive definition is:

    template <size_t nr, typename PolicyT1, typename ...PolicyTypes>
    struct MultiBase<nr, PolicyT1, PolicyTypes...> :
                                public UWrap<nr, PolicyT1>,
                                public MultiBase<nr + 1, PolicyTypes...>
    {
        typedef PolicyT1 Type;
        typedef MultiBase<nr + 1, typename PolicyTypes...> Base;

        MultiBase(PolicyT1 && policyt1, PolicyTypes &&...policytypes)
        :
            UWrap<nr, PolicyT1>(std::forward<PolicyT1>(policyt1)),
            MultiBase<nr + 1, PolicyTypes...>(
                              std::forward<PolicyTypes>(policytypes)...)
        {}
    };

23.10.3: Support templates

The Multi class template defines PlainTypes as the TypeList holding all the types of its parameter pack. Each MultiBase derived from a UWrap type also defines a type Type representing the policy type that was used to define the UWrap type and a type Base representing the type of its nested MultiBase class.

These three type definitions allow us to access the types from which the Multi object was created as well as the values of those types.

The class template typeAt, is a pure template meta program class template (it has no run-time executable code). It expects a size_t idx template argument specifying the index of the policy type in a Multi type object as well as a Multi class type. It defines the type Type as the Type defined by Multi's MultiBase<idx, ...> base class. Example:

    typeAt<0, Multi<Vector, int, double>>::Type // Type is vector<int>

The class template typeAt defines (and uses) a nested class template PolType doing all the work. PolType's generic definition specifies two template parameters: an index used to specify the index of the requested type and a typename initialized by a MultiBase type argument. PolType's recursive definition recursively reduces its index non-type parameter, passing the next base class in MultiBase's inheritance tree to the recursive call. As PolType eventually defines the type Type to be the requested policy type the recursive definition defines its Type as the type defined by the recursive call. The final (non-recursive) specialization defines the initial policy type of the MultiBase type as Type. Here is typeAt's definition:

    template <size_t index, typename Multi>
    class typeAt
    {
        template <size_t idx, typename MultiBase>
        struct PolType;

        template <size_t idx,
                  size_t nr, typename PolicyT1, typename ...PolicyTypes>
        struct PolType<idx, MultiBase<nr, PolicyT1, PolicyTypes...>>
        {
            typedef typename PolType<
                idx - 1, MultiBase<nr + 1, PolicyTypes...>>::Type Type;
        };

        template <size_t nr, typename PolicyT1, typename ...PolicyTypes>
        struct PolType<0, MultiBase<nr, PolicyT1, PolicyTypes...>>
        {
            typedef PolicyT1 Type;
        };
    public:
        typeAt(typeAt const &) = delete;
        typedef typename PolType<index, typename Multi::Base>::Type Type;
    };

The types specified by Multi's parameter pack can also be retrieved using a second helper class template: plainTypeAt. Example:

    plainTypeAt<0, Multi<Vector, int, double>>::Type // Type is int
The class template plainTypeAt uses a comparable (but simpler) implementation than typeAt. It is also a pure template meta program class template defining a nested class template At. At is implemented like typeAt but it visits the types of the original template pack that was passed to Multi, and made available by Multi as its PlainTypes type. Here is plainTypeAt's definition:
    template <size_t index, typename Multi>
    class plainTypeAt
    {
        template <size_t idx, typename List>
        struct At;

        template <size_t idx, typename Head, typename ...Tail>
        struct At<idx, TypeList<Head, Tail...>>
        {
            typedef typename At<idx - 1, TypeList<Tail...>>::Type Type;
        };

        template <typename Head, typename ...Tail>
        struct At<0, TypeList<Head, Tail...>>
        {
            typedef Head Type;
        };

    public:
        plainTypeAt(plainTypeAt const &) = delete;
        typedef typename At<index, typename Multi::PlainTypes>::Type Type;
    };

Arguably the neatest support template is get. This is a function template defining size_t idx as its first template parameter and typename Multi as its second template parameter. The function template get defines one function parameter: a reference to a Multi, so it can deduct Multi's type by itself. Knowing that it's a Multi, we reason that it is also a UWrap<nr, PolicyType> and therefore also a PolicyType, as the latter class is defined as a base class of UWrap.

Since class type objects can initialize references to their base classes the PolicyType & can be initialized by an appropriate UWrap reference, which in turn can be initialized by a Multi object. Since we can determine PolicyType using TypeAt (note that evaluating typename typeAt<idx, Multi>::Type is a purely compile-time matter), the get function can very well be implemented inline by a single return statement:

    template <size_t idx, typename Multi>
    inline typename typeAt<idx, Multi>::Type &get(Multi &multi)
    {
        return static_cast<
                UWrap<idx, typename typeAt<idx, Multi>::Type> &>(multi);
    }

The intermediate UWrap cast is required to disambiguate between identical policy types (like two vector<int> types). As UWrap is uniquely determined by its nr template argument and this is the number argument that is passed to get ambiguities can easily be prevented.

23.10.4: Using Multi

Now that Multi and its support templates have been developed, how can a Multi be used?

A word of warning is in place. To reduce the size of the developed classes they were designed in a minimalist way. For example, the get function template cannot be used with Multi const objects and there is no default, or move constructor available for Multi types. Multi was designed to illustrate some of the possibilities of template meta programming and hopefully Multi's implementation served that purpose well. But can it be used? If so, how?

This section provides some annotated examples. They may be concatenated to define a series of statements that could be placed in a main function's body, which would result in a working program.

23.11: Expression Templates

Assume we are processing std::vector objects. Vectors may be assigned to each other, but that's about it. We've seen (cf. section 12.4.2) that its member functions tend to operate on the current vector, but arithmetic operations like addition, subtraction, multiplication and the like cannot be applied to pairs of vectors.

Furtunately implementing, e.g., the addition operator for vectors is not particularly difficult. If VecType is our vector type, then implementing free functions like VecType operator+(VecType const &lhs, VecType const &rhs) and VecType operator+(VecType &&lhs, VecType const &rhs) performing the additions is a simple exercise (cf. chapter 11).

Now consider an expression like one + two + three + four. It takes four steps to compute this sum: first, tmp = one is computed, creating the eventual return value. The vector tmp is an (in practice anonymous) temporary variable. Then tmp += two is computed, followed by tmp += three, and finally by tmp += four, obtaining the final result (of course we shouldn't implement std::vector::operator+= as the std namespace is off-limits to us, and we shouldn't derive a class from std::vector offering operator+= according to Liskov's Substitution Principle (cf. section 14.7), but we could get around that, and here we simply assume operator+= is available).

Here's how we might implement operator+= for VecType:

    VecType &VecType::operator+=(VecType const &rhs)
    {
        for (size_t idx = 0, end = size(); idx != end; ++idx)
            (*this)[idx] += rhs[idx];
        return *this;
    }
Consider this implementation: once we add a VecType object and such objects have n elements then we have to perform 2 * n index evaluations. When adding k VecType objects this sums up to about 2 * k * n index expression evaluations: a lot of evaluations if we're adding many and/or big vectors.

If instead we could manage to perform the evaluations `row by row', each vector element would be accessed only once. This would dramatically cut down on our index evaluations. We would only need to perform approx. n * k index expression evaluations.

Expression templates allow us to achieve precisely this kind of optimization. We'll have a look at their design and implementation in the coming sections.

23.11.1: Designing an Expression Template

As we've seen, when using a standard implementation of an expression like one + two + three + four, where the objects are vectors having n elements, then if we have k vectors we have to perform a total of k * 2 * n index evaluations.

Expression templates allow us to avoid many of these evaluations. When using expression templates these templates may access the vectors, but their elements are not accessed during addition operations.

Assuming our expression template is named ET, and we want to add one + two + three, then the first + operator merely creates ET(one, two). Note that no addition is actually performed, ET merely stores (constant) references to one (becoming ET's lhs data member) and two (becoming ET's rhs data member). In general, ET stores references to the two arguments that are passed to its constructor.

At the next addition operator another ET is created. Its constructor arguments are, respectively, the ET object that has just been constructed for one and two, and the vector three. Again, no addition is performed by the ET objects.

This algorithm easily generalizes to any number of vectors. Parentheses can also be used. E.g., (one + two) + (three + four) results in

    ET(ET(one, two), ET(three, four))

Presumably, at some point we want to obtain the sum of the vectors. For this the expression template is provided with a conversion operator, converting the ET object to a vector, or maybe an assignment operator doing the same.

The conversion operator looks like this:

    operator ET::VecType() const
    {                                                        
        VecType retVal;
        retVal.reserve(size());

        for (size_t ix = 0, end = size(); ix != end; ++ix)
            new(&retVal[ix]) value_type((*this)[ix]);
                                                     
        return retVal;
    }
Placement new is used for efficiency reasons: there's no need to initialize retVal with default values first. The really interesting part, however, is hidden behind the (*this)[idx] expression: at this point the real addition takes place.

ET's index operator simply adds the values returned by the corresponding index expressions of its lhs and rhs data members. If a data member refers to a vector then the corresponding vector element is used, adding it to the other data member's value. If a data member itself refers to an ET object, then that nested ET object's index operator performs the same addition on its own data members, returning their sum. So, an expression like (*this)[0] returns first[0] + second[0] + third[0], and the computed sum is then stored in retVal[0] using placement new.

In this case the required number of index expression evaluations are n * k (for the n elements of the k vectors) plus n (for the n elements of retVal, adding up to (k + 1) * n).

Since (k + 1) * n < 2 * k * n for k > 1 expression templates evaluate the requested addition more efficiently than the traditional implementation of operator+. An additional benefit of using expression templates is that they do not create additional temporary vector objects when parenthesized expressions are used.

23.11.2: Implementing an Expression Template

In this section we use a typedef std::vector<int> IntVect to illustrate the construction of an expression template.

Starting point is a simple main function, in which several IntVect objects are added. E.g.,

    int main()
    {
        IntVect one;
        IntVect two;
        IntVect three;
        IntVect four;
        
        // ... assume the IntVects somehow receive values

        four = one + two + three + four;
    }
At this point the code does not suggest that expression templates are going to be used. However, operator+'s implementation is special: it's a template merely returning an object constructed by operator+:
    template<typename LHS, typename RHS>
    BinExpr<LHS, RHS, plus>  operator+(LHS const &lhs, RHS const &rhs)
    {
        return BinExpr<LHS, RHS, plus>(lhs, rhs);
    }

Our expression template is called BinExpr. It has three template type parameters: two object types and a template template parameter performing the requested operation. Its declaration looks like this:

    template<typename LHS, typename RHS, template<typename> class Operation>
    struct BinExpr;
Since LHS and RHS can either be the data type that is processed by the expression template, or a BinExpr two different typenames are required. Operation is the operation that is performed by the expression template. By using a template template parameter we can use BinExpr to perform any operation we want, not just addition. Predefined function templates like std::plus can be used for the standard arithmetic operators; for other operators we can define our own function templates.

BinExpr's constructor initializes constant references to lhs and rhs. Its in-class implementation is

    BinExpr(LHS const &lhs, RHS const &rhs)
    :
        d_lhs(lhs),
        d_rhs(rhs)
    {}

To retrieve the resulting IntVect a conversion operator is defined. We already encountered its implentation (in the previous section). Here is it, as an in-class implemented BinExpr member:

    operator ObjType() const
    {                                                        
        ObjType retVal;
        retVal.reserve(size());

        for (size_t idx = 0, end = size(); idx != end; ++idx)
            new(&retVal[idx]) value_type((*this)[idx]);
                                                     
        return retVal;
    }
We return to the type ObjType below. At this point it can be considered an IntVect. The member size() simply returns d_lhs.size(): in any sequence of IntVect additions LHS eventually is an IntVect, and so every BinExpr defines a valid size() like so:
    size_t size() const
    {
        return d_lhs.size();
    }

The only remaining member to implement is operator[]. Since it receives an index, it only needs to perform the requested operation on the corresponding index elements of its d_lhs and d_rhs data members. The beauty of expression templates is that if either one itself is a BinExpr that expression template in turn calls its operator[], eventually performing the requested operation on all corresponding elements of all IntVect objects. Here is its implementation:

    value_type operator[](size_t ix) const
    {
        static Operation<value_type> operation;

        return operation(d_lhs[ix], d_rhs[ix]);
    }
This implementation uses another type: value_type which is the type of the elements of the vector type that is processed by the expression template. Like ObjType before, its definition is covered below. The static data member operation simply is an instantiation of the Operation type that is specified when constructing an ExprType object.

So, it's about time to have a look at ObjType and value_type. We do that in the next section.

23.11.3: The BasicType trait class and ordering classes

The BinExpr expression template needs to be aware of two types before it can instantiate objects. First, ObjType must be known, as this is the type of object that is handled by the expression template. ObjType objects contain values, and we require that the type of these values can be determined as ObjType::value_type. E.g., for our IntVect data type value_type is int.

In expressions like one + two + three, the BinExpr expression template receives two IntVect objects. This is always true: the BinExpr that is first constructed receives two IntVect objects. In this case ObjType is simply LHS, and ObjType::value_type is also available: either value_type is already defined by LHS or BinExpr requires that it defines type value_type.

Since arguments to BinExpr objects are not always of the basic ObjType type (BinExpr objects at the next nesting level receive at least one BinExpr argument) we need a way to determine ObjType from a BinExpr. For this we use a trait class. The trait class BasicType receives a typename template argument, and equates its type ObjType to the received template type argument:

    template<typename Type>
    struct BasicType
    {
        typedef Type ObjType;
    };
A specialization handles the cae where Type in fact is a BinExpr: template<typename LHS, typename RHS, template<typename> class Operation>
    template<typename LHS, typename RHS, template<typename> class Operation>
    struct BasicType<BinExpr<LHS, RHS, Operation>>
    {
        typedef typename BinExpr<LHS, RHS, Operation>::ObjType ObjType;
    };

Since BinExpr requires that ObjType::value_type is a defined type, value_type has automatically been taken care of.

As BinExpr refers to BasicType and BasicType refers to BinExpr somewhere we must provide a forward declaration. As BinExpr's declaration has already been provided, we start with that declaration, resulting in:

    BinExpr's declaration

    BasicType's definition

    BasicType's specialization (for BinExpr)

    template<typename LHS, typename RHS, template<typename> class Operation>
    class BinExpr 
    {
        LHS const &d_lhs;
        RHS const &d_rhs;

        public:
            typedef typename BasicType<RHS>::DataType DataType;
            typedef typename DataType::value_type value_type;

            // all BinExpr member functions
    };