Previous section   Next section

Imperfect C++ Practical Solutions for Real-Life Programming
By Matthew Wilson
Table of Contents
Chapter 16.  Keywords


16.7. Unsupported Keywords

Since we live in the real world, where different compilers have different levels of support for various language features, we have to find mechanisms for working with and without support for keywords, especially those most lately introduced.

Imperfection: The introduction of new keywords into the language requires contingency mechanisms to maintain portability.


16.7.1 typename

Although the three keywords mutable, explict and typename were introduced to compilers at the same time, typename still is not fully supported on some compilers in common use.[4]

[4] Borland (including 5.6), Visual C++ 6, and Watcom.

There are four contexts within which typename is meaningful.

  1. As a replacement for the class keyword in template parameter lists. In this guise typename, when provided, works correctly on all compilers that I am familiar with.

  2. As a type qualifier [Aust1999] within template function bodies.

  3. As a type qualifier in template function signatures and return types

  4. As a type qualifier in template parameter default arguments.

Context 1, 2, and 3 look like the following:



template <typename /* 1 */ T>


typename /* 2 */ T::size_type get_sizeof(T const &t)


{


  typename /* 3 */ T::size_type si = sizeof(t);


  return si;


}



Contexts 2 and 3 are used to inform the compiler that the particular identifier being qualified is a type of the given type, rather than, a member. This is because the default interpretation prescribed by the language is that a qualified symbol is a member, rather than a type. In almost all cases where the use of the keyword is supported in (2), it is in (3). However, it is only in very recent compilers where (2) is mandated, as it should be. As of the time of writing, Visual C++ 7.1 is the most correct, with CodeWarrior and GCC very close seconds.

The final case is the strangest. It looks like the following example



template< typename /* 1 */ S


        , typename /* 1 */ C = typename /* 4 */ S::value_type


        , typename /* 1 */ T = char_traits<C>


        >


class fast_string_concatenator;



This tells the compiler that value_type is a member type of S. Again there is much equivocation on the validity of the use of typename in this context, though it does not detract from a correct interpretation of the template—at last not with any that I have ever presented to such a compiler—so the answer is to use compiler-dependent macros.

For example, the STLSoft libraries define the pseudokeyword preprocessor symbols ss_typename_param_k (1), ss_typename_type_k (2) and (3), and ss_typename_type_def_k (4) for these contexts, which are defined as typename for those compilers that correctly support it, or as class (for 1) and nothing (for (2)–(4)). This allows library code to be as neat as possible—which is not very neat when complex templates are involved—and localizes the environment specific features in one place. The names represent a compromise between readability and uniqueness.


      Previous section   Next section