Это потому, что класс ConcreteTable еще не создан при создании экземпляра Table, поэтому компилятор еще не видит T :: RT. Я не совсем уверен, как именно стандарт C ++ обрабатывает такую рекурсию (я подозреваю, что она не определена), но она не работает так, как вы ожидаете (и это, вероятно, хорошо, иначе все было бы намного сложнее - вы могли выразить с ним логический парадокс - как const bool, который является ложным, если это правда).
Крепежный
С typedefs, я думаю, вы не можете надеяться на большее, чем просто передать RT в качестве дополнительного параметра шаблона, например,
template <class T, class RT>
class Table
{
public:
typedef typename RT Zot;
};
class ConcreteTable : public Table<ConcreteTable, Record>
{
public:
typedef Record RT;
};
Если вы не настаиваете на доступности RT как Table<>::Zot
, вы можете поместить его во вложенную структуру
template <class T>
class Table
{
public:
struct S {
typedef typename RT Zot;
};
};
class ConcreteTable : public Table<ConcreteTable>
{
public:
typedef Record RT;
};
Или даже структура внешних черт
template <class T>
struct TableTraits<T>;
template <class T>
struct TableTraits<Table<T> > {
typedef typename T::RT Zot;
};
Если вы хотите, чтобы тип был только аргумент / возвращаемый тип метода, вы можете сделать это с помощью шаблона этого метода, например.
void f(typename T::RT*); // this won't work
template <class U>
void f(U*); // this will
Смысл всех этих манипуляций состоит в том, чтобы отложить необходимость в T :: RT как можно позже, особенно до тех пор, пока ConcreteTable не станет полным классом.