A name in C++ can pertain to three different tiers of entities: Types, values, and templates.
struct Foo
{
typedef int A; // type
static double B; // value
template <typename T> struct C; // template
};
The three names Foo::A
, Foo::B
and Foo::C
are examples of all three different tiers.
In the above example, Foo
is a complete type, and so the compiler knows already what Foo::A
etc. refer to. But now imagine this:
template <typename T> struct Bar
{
T::A x;
};
Now we are in trouble: what is T::A
? if T = Foo
, then T::A = int
, which is a type, and all is well. But when T = struct { static char A; };
, then T::A
is a value, which doesn't make sense.
Therefore, the compiler demands that you tell it what T::A
and T::B
and T::C
are supposed to be. If you say nothing, it is assumed to be a value. If you say typename
, it is a typename, and if you say template
, it is a template:
template <typename T> struct Bar
{
typename T::A x; // ah, good, decreed typename
void foo()
{
int a = T::B; // assumed value, OK
T::template C<int> z; // decreed template
z.gobble(a * x);
}
};
Secondary checks such as whether T::B
is convertible to int
, whether a
and x
can be multiplied, and whether C<int>
really has a member function gobble
are all postponed until you actually instantiate the template. But the specification whether a name denotes a value, a type or a template is fundamental to the syntactic correctness of the code and must be provided right there during the template definition.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…