#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;
}