B.2. The RulesIn 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. typenameThe relevant standard language comes from section 14.6 [temp.res], paragraph 5:
B.2.1.1 typename RequiredThe 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 Forbiddentypename 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]
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
B.2.2. templateThe relevant standardese comes from section 14.2 [temp.names] of the C++ standard, in paragraph 4:
and paragraph 5:
Core language issue #30 adds:[6]
B.2.2.1 template RequiredThe 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 ForbiddenThe 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]
![]() |