Это из-за двухфазного поиска имени в шаблонах. Когда компилятор видит Innerclass, он должен знать, является ли это имя типом или нет (это может быть, например, статический член типа int для некоторой специализации OuterClass). Таким образом, предполагается, что это НЕ имя типа, если вы не говорите так. typename должно использоваться в шаблонах и только для имен, зависящих от параметра шаблона. НТН
пример:
template <class T>
class X
{
typedef T XXX;
};
template<>
class X<char>
{
static int XXX;
};
template<class T>
class Y
{
// X<T>::XXX member; invalid XXX is not assumed to be a type!
typename X<T>::XXX member;
//we explicitly specify that XXX is a type; Later, upon instantiation, we will verify that
};