Section B.2.  The Rules
Team LiB
Previous Section Next Section

B.2. The Rules

In this section we'll cover the standard's rules for the use of template and typename and walk through some illustrative examples.

B.2.1. typename

The relevant standard language comes from section 14.6 [temp.res], paragraph 5:

The keyword typename shall only be used in template declarations and definitions, including in the return type of a function template or member function template, in the return type for the definition of a member function of a class template or of a class nested within a class template, and in the type-specifier for the definition of a static member of a class template or of a class nested within a class template. The keyword typename shall only be applied to qualified names, but those names need not be dependent. The keyword typename is not permitted in a base-specifier or in a mem-initializer; in these contexts a qualified-name that depends on a template-parameter (14.6.2) is implicitly assumed to be a type name.

B.2.1.1 typename Required

The typename keyword is required anywhere in templates on qualified dependent names that denote types.

Identifying Dependent Type Names

In the following example, the type C::value_type is dependent on the template parameter C.



   // member data declarations


   template <class C>


   struct something


   {


       typename C::value_type x;


   };



The property of being a dependent type is transitive. In the following example, C::value_type is dependent on C and value_type::is_const is dependent on value_type (and therefore also on C).



   // member type declarations


   template <class C>


   struct something


   {


       typedef typename C::value_type value_type;


       typedef typename value_type::is_const is_const;


   };



In the following example, the ::type member of the add_const metafunction is dependent on the template parameter T.



   template <class T>


   struct input_iterator_part_impl


   {


       typedef typename boost::add_const<T>::type const_T;


   };



Contexts for Application

You've seen how typename is applied within class template bodies. It is also required within parameter lists, including in default argument expressions:



   template <


         class T


       , typename non_type_parameter<T>::type value


           = typename non_type_parameter<T>::type()


   >


   struct initialized


   {};



and in function templates, including their bodies:



   template <class Sequence>


   typename Sequence::iterator          // in return type


   find(


       Sequence seq


     , typename Sequence::value_type x  // in parameter types


   )


   {


       typename Sequence::iterator it   // inside function body


         = seq.begin();


       ...etc...


   }



Since the rule is "one typename per dependent name," there might be several typenames required within a single declaration.



   template <class Sequence>


   struct key_iterator_generator


   {


       typedef typename projection_iterator_gen<


           select1st<typename Sequence::value_type>


         , typename Sequence::const_iterator


       >::type type;


   };



Subtleties

A type can be dependent for subtle reasons. In the following example, index<1>::type is dependent because one can specialize the index member template for a given Iterator type.



   template <class Iterator>


   struct category_index


   {


       template <long N> struct index


       {


           typedef char(&type)[N];


       };





       static typename index<1>::type


       category(std::input_iterator_tag);


       static typename index<2>::type


       category(std::forward_iterator_tag);


   };





   template <>


   template <long N>


   struct category_index<int*>::index


   {


       typedef char(&type)[N + 1];


   };



In other words, for the purpose of syntax disambiguation, the primary category_index template is equivalent to:



   template <class Iterator, long N> struct index


   {


       typedef char(&type)[N];


   };





   template <class Iterator>


   struct category_index


   {


       static typename index<Iterator,1>::type


       category(std::input_iterator_tag);





       static typename index<Iterator,2>::type


       category(std::forward_iterator_tag);


   };



B.2.1.2 typename Allowed (But Not Required)

The typename keyword is optional on qualified non-dependent names inside a template. In the following example, std::unary_function<T,T*> is not dependent because it is always a class, no matter what T turns out to be.



   template <class T>


   struct something


   {


       // OK


       std::unary_function<T,T*> f2;


       std::unary_function<int,int>::result_type x2;


       // also OK


       typename std::unary_function<T,T*> f1;


       typename std::unary_function<int,int>::result_type x1;


   };



B.2.1.3 typename Forbidden

typename cannot be used anywhere outside of templates:



   struct int_iterator


   {


       typedef typename int value_type; // error


   };



It is also forbidden on non-qualified names (those not preceded by ::), even if they are dependent.



   template <class T>


   struct vector


   {


       typedef typename int value_type;        // error


       typedef typename pair<int,T> pair_type; // error


       typedef typename T* pointer;            // error


   };



typename is forbidden on the name of a base class, even if it is dependent:



   template <class T> struct base_gen;





   template <class T>


   struct derived


     : typename base_gen<T>::type // error


   {};



but in the following, typename is required because T::value_type does not name a base class.



   template <class T>


   struct get_value


     : std::unary_function<T, typename T::value_type> // OK


   {};



Since an explicit (full) specialization is not a template declaration, the following is not currently allowed, though core language issue #183 argues in favor of allowing it in future revisions of the standard.[3]

[3] See http://www.open-std.org/jtcl/sc22/wg21/docs/cwg_defects.html#183.



   template <class T> struct vector;





   template <class T> struct vector_iterator


     : mpl::identity<T> {};








   template <>


   struct vector<void*>


   {


       typedef typename                          // error


         vector_iterator<void*>::type iterator;


   };



B.2.1.4 Miscellaneous Notes
  • The C++ standard (section 14.6.1) allows us to use a class template's own name without arguments as a synonym for the specialization being instantiated, which means we can use a template's name to qualify members of dependent bases. For instance, instead of:

    
    
       template <class T> class base;
    
    
    
    
    
       template <class T>
    
    
       struct derived
    
    
         : base<typename whatever<T>::type> // repeated below
    
    
       {
    
    
           typedef base<typename whatever<T>::type> base_;
    
    
           typedef typename base_::value_type value_type;
    
    
       };
    
    
    

    we can simply write:

    
    
       template <class T> struct base;
    
    
    
    
    
       template <class T>
    
    
       struct derived
    
    
         : base<typename whatever<T>::type> // not repeated
    
    
       {
    
    
           typedef typename derived::value_type value_type;
    
    
       };
    
    
    

  • with the acceptance of core language issue #11,[4]

    [4] See http://www.open-std.org/jtcl/sc22/wg21/docs/cwg_defects.html#11.

    
    
       template class T> struct base;
    
    
    
    
    
       template <class T>
    
    
       struct derived
    
    
         : base<T>
    
    
       {
    
    
           using typename base<T>::value_type;
    
    
       };
    
    
    

    is equivalent to

    
    
       template <class T> struct base;
    
    
    
    
    
       template <class T>
    
    
       struct derived
    
    
         : base<T>
    
    
       {
    
    
           typedef typename base<T>::value_type value_type;
    
    
       };
    
    
    

  • core language issue #180 clarifies that typename is not allowed in friend declarations,[5] e.g.:

    [5] See http://www.open-std.org/jtcl/sc22/wg21/docs/cwg_defects.html#180.

    
    
       template <class T>
    
    
       class X
    
    
       {
    
    
           friend class typename T::nested; // error
    
    
       };
    
    
    

B.2.2. template

The relevant standardese comes from section 14.2 [temp.names] of the C++ standard, in paragraph 4:

When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a nontemplate.

and paragraph 5:

If a name prefixed by the keyword template is not the name of a member template, the program is ill-formed. [Note: the keyword template may not be applied to nontemplate members of class templates.]

Core language issue #30 adds:[6]

[6] See http://www.open-std.org/jtcl/sc22/wg21/docs/cwg_defects.html#30.

Furthermore, names of member templates shall not be prefixed by the keyword template if the postfix-expression or qualified-id does not appear in the scope of a template. [Note: just as is the case with the typename prefix, the template prefix is allowed in cases where it is not strictly necessary; i.e., when the expression on the left of the -> or ., or the nested-name-specifier is not dependent on a template-parameter. ]

B.2.2.1 template Required

The template keyword is required before dependent names accessing member templates via ., ->, or :: qualification. In the following example, convert and base depend on T.



   template <class T> void f(T& x, T* y)


   {


       int n = x.template convert<int>();


       int m = y->template convert<int>();


   }





   template <class T> struct other;


   template <class T>


   struct derived


     : other <T>::template base<int>


   {};



Note that, unlike the typename keyword, template is required even on class template names that denote base classes.

B.2.2.2 template Allowed (But Not Required)

As long as it actually precedes a member template id, template is optional anywhere in a template. For instance:



   template <class T>


   struct other


   {


      template <class T> struct base;


   };





   template <class T>


   struct derived1


     : other<int>::base<T>               // OK


   {};





   template <class T>


   struct derived2


     : other <int>::template base<T>    // also OK


   {};



B.2.2.3 template Forbidden

The template keyword is forbidden anywhere outside a template, including explicit (full) template specializations (as per core language issue #30 cited earlier):



   template <> struct derived<int>


     : other<int>::template base<int> // error


   {};



template is also forbidden in using-declarations:



   template <class T>


   struct derived


     : base<T>


   {


       using base<T>::template apply; // error


   };



This ban was clarified by core language issue #109 as Not a Defect (NAD).[7]

[7] See http://www.open-std.org/jtcl/sc22/wg21/docs/cwg_closed.html#109.

    Team LiB
    Previous Section Next Section