использование имени типа из параметра шаблона в классе

#c

#c

Вопрос:

 //A.h
template <class T>
class A
{
public:
    typename T::Type x; //(1) compile time error: C2039 'Type': is not a member of 'B'
    void f();
};
template <class T>
void A<T>::f() 
{ 
  typename T::Type x1; //(2) but no errors here
}

//B.h 
#include "A.h"

class B : public A<B>
{
public:
    using Type = int;
};

//main.cpp
#include "B.h"

int main()
{
    B x;
}
  

Почему в (1) есть ошибка, но нет ошибок в (2)?
Как я могу сохранить переменную типа typename T::Type и написать функцию, как func(typename T::Type) в классе?

Я не знаю, почему был сделан этот дизайн класса, и я не хочу изменять иерархию классов или параметры шаблона в коде, потому что существует много классов, унаследованных от A, и код довольно запутанный. Поэтому, пожалуйста, никаких советов таким образом.

PS Извините за неясное название вопроса, но я не могу придумать лучшего.

Комментарии:

1. Для определения A, B::Type должен быть известен. Для определения B должно быть известно <B> . Это неразрешимо. Определения обоих типов зависят друг от друга и, следовательно, не могут быть разрешены.

Ответ №1:

Пока вы определяете class B : public A<B> , класс B не определен, но вы пытаетесь использовать этот класс в A. На данный момент компилятор не знает, будет ли определение using Type = int; .

gcc предоставляет более читаемое сообщение об ошибке: «недопустимое использование неполного типа ‘class B'»

void A<T>::f() никогда не будет создан экземпляр, поэтому вы не увидите сообщение об ошибке.

Плохая новость: у вас нет возможности выполнить какое-либо прямое объявление в этой ситуации, поскольку у вас полная циклическая зависимость.

Ответ №2:

 class B : public A<B>
  

B на данный момент является неполным. Пока неизвестно, есть ли у него Type член. Таким образом, создание экземпляра A::x завершается неудачно.

В отличие от этого, A<T>::f() никогда не создается экземпляр. Если вы создаете его экземпляр, это, вероятно, произойдет, когда B это полный тип, поэтому B::Type уже должно быть известно.

Ответ №3:

Вы не можете этого сделать из-за цикличности в определениях — A<B> не может быть определено, пока B не определено, и B не может быть определено, пока A<B> не определено.

Что вы можете сделать, так это добавить уровень косвенности, проходя через класс «черты», который не зависит от окончательного определения B .

Пример:

 template <typename T>
struct traits{};

template <class T>
class A
{
public:
    typename traits<T>::Type x; 
};

class B;

template <>
struct traits<B>
{
    using Type = int;
};

class B : public A<B>
{
public:
    using Type = typename traits<B>::Type;
};


int main()
{
    B x;
}