Потому что, как и сообщение об ошибке, List<dataType>::Node
является зависимым именем , то есть тем, что зависит от параметра шаблона. Представьте, что вы что-то вроде этого:
struct A {
typedef float t;
};
struct B {
static int t;
};
template <typename T>
void func()
{
T::t * x; // pointer declaration, or multiplication? It depends...
}
Здесь A::t
и B::t
являются оба корректными выражениями C++, но означают совершенно разные вещи: первый тип, а второй имеет значение. Теперь, когда компилятор сначала анализирует функцию шаблона func()
- чтобы проверить, является ли он синтаксически правильным, перед выполнением любой замены типа - он должен попытаться решить, что означает T::t * x
. Ясно, что есть два возможных способа разобрать его, поэтому компилятор должен решить, что взять.
В некоторых случаях для компилятора достаточно «контекста», чтобы решить, ссылаетесь ли вы на тип или нет, но во многих случаях (например, этот пример) этого не происходит. Когда он не может решить, он предполагает, что вы говорите о значении - поэтому выше (надеюсь) даст вам ошибку об изменении переменной x
. Если вы хотите, чтобы T::t
рассматривался как тип, вам нужно указать его так явно, используя ключевое слово typename
.
'Этот код выглядит так, как будто он должен компилироваться, но он неверен, потому что компилятор не знает, является ли T :: bar типом или значением.' – Gasim
Правило большого пальца: возьмите самый правый '::'; если предмет справа от него - это тип, а вещь слева от него зависит от параметров шаблона каким-либо образом, используйте 'typename'. – Angew