![]() | |
![]() ![]() |
![]() | Imperfect C++ Practical Solutions for Real-Life Programming By Matthew Wilson |
Table of Contents | |
Chapter 16. Keywords |
16.7. Unsupported KeywordsSince 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.
16.7.1 typenameAlthough 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]
There are four contexts within which typename is meaningful.
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. ![]() |
![]() | |
![]() ![]() |