A name в C ++ может относиться к трем различным уровням сущностей: значениям, типам и шаблонам.
struct Foo
{
typedef int A;
static double B;
template <typename T> struct C;
};
Три имени Foo::A
, Foo::B
и Foo::C
являются примерами всех трех разных уровней.
В приведенном выше примере Foo
является полным типом, и поэтому компилятор уже знает, на что ссылаются Foo::A
и т. Д. Но теперь представьте себе:
template <typename T> struct Bar
{
T::A x;
};
Теперь у нас проблемы: что такое T::A
? если T = Foo
, то T::A = int
, который является типом, и все хорошо. Но когда T = struct { char A; };
, тогда T::A
- это значение , что не имеет смысла.
Следовательно, компилятор требует, чтобы вы сообщили ему, что T::A
и T::B
и T::C
должны быть. Если вы ничего не говорите, это считается значением. Если вы говорите typename
, это имя типа, а если вы говорите 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);
}
};
Вторичные проверки, например, можно ли преобразовать T::B
в int
, можно ли умножить a
и x
, и есть ли у C<int>
функция-член gobble
, все откладываются до тех пор, пока вы фактически не создадите экземпляр шаблон. Но указание, обозначает ли имя значение, тип или шаблон, является основополагающим для синтаксической правильности кода и должно быть предоставлено прямо во время определения шаблона.