C++ Templates
Authors: Vandevoorde D. Josuttis N.M.
Published year: 2002
Pages: 35-37/185
Buy this book on amazon.com >>
Ru-Brd

4.4 Summary

  • Templates can have template parameters that are values rather than types.

  • You cannot use floating-point numbers , class-type objects, and objects with internal linkage (such as string literals) as arguments for nontype template parameters.

Ru-Brd
Ru-Brd

Chapter 5. Tricky Basics

This chapter covers some further basic aspects of templates that are relevant to the practical use of templates: an additional use of the typename keyword, defining member functions and nested classes as templates, template template parameters, zero initialization, and some details about using string literals as arguments for function templates. These aspects can be tricky at times, but every day-to-day programmer should have heard of them.

Ru-Brd
Ru-Brd

5.1 Keyword typename

The keyword typename was introduced during the standardization of C++ to clarify that an identifier inside a template is a type. Consider the following example:

template <typename T> 
class MyClass { 
   typename T::SubType * ptr;


};

Here, the second typename is used to clarify that SubType is a type defined within class T . Thus, ptr is a pointer to the type T::SubType .

Without typename , SubType would be considered a static member. Thus, it would be a concrete variable or object. As a result, the expression

T::SubType * ptr

would be a multiplication of the static SubType member of class T with ptr .

In general, typename has to be used whenever a name that depends on a template parameter is a type. This is discussed in detail in Section 9.3.2 on page 130.

A typical application of typename is the access to iterators of STL containers in template code:


// basics/printcoll.hpp

#include <iostream>

// print elements of an STL container

template <typename T> 
void printcoll (T const& coll) 
{ 
    typename T::const_iterator pos;

// iterator to iterate over

coll 
    typename T::const_iterator end(coll.end());

// end position

for (pos=coll.begin(); pos!=end; ++pos) { 
        std::cout << *pos << ' '; 
    } 
    std::cout << std::endl; 
}

In this function template, the call parameter is an STL container of type T . To iterate over all elements of the container, the iterator type of the container is used, which is declared as type const_iterator inside each STL container class:

class

stlcontainer

{


typedef


iterator;

// iterator for read/write access

typedef


const_iterator;

// iterator for read access



};

Thus, to access type const_iterator of template type T , you have to qualify it with a leading typename :

typename T::const_iterator pos;

The .template Construct

A very similar problem was discovered after the introduction of typename . Consider the following example using the standard bitset type:

template<int N> 
void printBitset (std::bitset<N> const& bs) 
{ 
    std::cout << bs.template to_string<char,char_traits<char>, 
                                       allocator<char> >(); 
}

The strange construct in this example is .template . Without that extra use of template , the compiler does not know that the less-than token ( < ) that follows is not really "less than" but the beginning of a template argument list. Note that this is a problem only if the construct before the period depends on a template parameter. In our example, the parameter bs depends on the template parameter N .

In conclusion, the .template notation (and similar notations such as ->template ) should be used only inside templates and only if they follow something that depends on a template parameter. See Section 9.3.3 on page 132 for details.

Ru-Brd
C++ Templates
Authors: Vandevoorde D. Josuttis N.M.
Published year: 2002
Pages: 35-37/185
Buy this book on amazon.com >>

Similar books on Amazon