Это на самом деле не связано с доступностью и дружбой, это связано с использованием CRTP. Рассмотрим следующий пример, который также демонстрирует проблему:
template <class T>
struct Base
{
typedef typename T::Data Data;
};
struct ThisWontCompile : public Base<ThisWontCompile>
{
struct Data { };
};
Проблема в том, что ThisWontCompile
является неполным в то время, когда оно используется в качестве аргумента шаблона для Base
, поэтому его можно использовать только как неполный тип в Base
.
Чтобы найти несколько решений вашей конкретной проблемы, обратитесь к ответам на этот другой вопрос , особенно к рекомендации Мартина использовать класс черт, который в основном будет выглядеть так:
// Base
template <typename T>
struct BaseTraits;
template <typename T>
struct Base
{
typedef typename BaseTraits<T>::Data Data;
};
// Derived
struct Derived;
template <>
struct BaseTraits<Derived>
{
struct Data { };
};
struct Derived : public Base<Derived>
{
};
typename BaseTraits<Derived>::Data
может использоваться как в Derived
, так и в Base
. Если Derived
сам является шаблоном, вы можете использовать частичную специализацию для класса черт.