1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
Until now the keyword tt(typename) has been used to indicate a template type
parameter. However, it is also used to
hi(typename: disambiguating code)
disambiguate code inside templates. Consider the following function template:
verb( template <typename Type>
Type function(Type t)
{
Type::Ambiguous *ptr;
return t + *ptr;
})
When this code is processed by the compiler, it complains with an -at
first sight puzzling- error message like:
verb( 4: error: 'ptr' was not declared in this scope)
The error message is puzzling as it was the programmer's intention to
declare a pointer to a type tt(Ambiguous) defined within the class template
tt(Type). But the compiler, confronted with tt(Type::Ambiguous) may interpret
the statement in various ways. Clearly it cannot inspect tt(Type) itself
trying to uncover tt(Type)'s true nature as tt(Type) is a template
type. Because of this tt(Type)'s actual definition isn't available yet.
The compiler is confronted with two possibilities: either
tt(Type::Ambiguous) is a em(static member) of the as yet mysterious template
tt(Type), or it is a em(subtype) of tt(Type). As the standard
specifies that the compiler must assume the former, the statement
verb( Type::Ambiguous *ptr;)
is interpreted as a em(multiplication) of the static member
tt(Type::Ambiguous) and the (now undeclared) entity tt(ptr). The reason for
the error message should now be clear: in this context tt(ptr) is unknown.
To disambiguate code in which an identifier refers to a
hi(template: identifying subtypes)
hi(class template: identifying subtypes)
hi(typename: and template subtypes)
subtype of a template type parameter the keyword tt(typename) must be
used. Accordingly, the above code is altered into:
verb( template <typename Type>
Type function(Type t)
{
typename Type::Ambiguous *ptr;
return t + *ptr;
})
Classes fairly often define subtypes. When such subtypes appear inside
template definitions as subtypes of template type parameters the tt(typename)
keyword em(must) be used to identify them as subtypes. Example: a class
template tt(Handler) defines a tt(typename Container) as its template type
parameter. It also defines a data member storing the iterator returned by the
container's tt(begin) member. In addition tt(Handler) offers a constructor
accepting any container supporting a tt(begin) member. tt(Handler)'s class
interface could then look like this:
verb( template <typename Container>
class Handler
{
Container::const_iterator d_it;
public:
Handler(Container const &container)
:
d_it(container.begin())
{}
};)
What did we have in mind when designing this class?
itemization(
it() The typename tt(Container) represents any container supporting
iterators.
it() The container presumably supports a member tt(begin). The
initialization tt(d_it(container.begin())) clearly depends on the
template's type parameter, so it's only checked for basic syntactic
correctness.
it() Likewise, the container presumably supports a em(subtype)
tt(const_iterator), defined in the class tt(Container).
)
The final consideration is an indication that tt(typename) is required. If
this is omitted and a tt(Handler) is instantiated the compiler produces a
peculiar compilation error:
verb( #include "handler.h"
#include <vector>
using namespace std;
int main()
{
vector<int> vi;
Handler<vector<int> > ph{ vi };
}
/*
Reported error:
handler.h:4: error: syntax error before `;' token
*/)
Clearly the line
verb( Container::const_iterator d_it;)
in the class tt(Handler) causes a problem. It is interpreted by the
compiler as a em(static member) instead of a subtype. The problem is
solved using tt(typename):
verb( template <typename Container>
class Handler
{
typename Container::const_iterator d_it;
...
};)
An interesting illustration that the compiler indeed assumes tt(X::a) to
be a member tt(a) of the class tt(X) is provided by the error message we get
when we try to compile tt(main) using the following implementation of
tt(Handler)'s constructor:
verb( Handler(Container const &container)
:
d_it(container.begin())
{
size_t x = Container::ios_end;
}
/*
Reported error:
error: `ios_end' is not a member of type `std::vector<int,
std::allocator<int> >'
*/)
Now consider what happens if the function template introduced at the
beginning of this section doesn't return a tt(Type) value, but a
tt(Type::Ambiguous) value. Again, a subtype of a template type is referred to,
and tt(typename) must be used:
verb( template <typename Type>
typename Type::Ambiguous function(Type t)
{
return t.ambiguous();
})
tt(Typename)s can be embedded in using declarations. As is often the case,
this
hi(template: embedded in using declarations)
reduces the complexities of declarations and definitions appearing
elsewhere. In the next example the type tt(Iterator) is defined as a subtype
of the template type tt(Container). tt(Iterator) may now be used without
requiring the use of the keyword tt(typename):
verb( template <typename Container>
class Handler
{
using Iterator = Container::const_iterator;
Iterator d_it;
...
};)
|