Распространение 'typedef' из базового в производный класс для 'template' - PullRequest
56 голосов
/ 29 октября 2009

Я пытаюсь определить базовый класс, который содержит только typedef.

template<typename T>
class A
{
public:
    typedef std::vector<T> Vec_t;
};


template<typename T>
class B : public A<T>
{
private:
    Vec_t v;  // fails - Vec_t is not recognized
};

Почему в B я получаю сообщение об ошибке, что Vec_t не распознается, и мне нужно написать это явно?

typename A<T>::Vec_t v;

Ответы [ 7 ]

43 голосов
/ 29 октября 2009

Я считаю, что этот вопрос дублирует, но я не могу найти его сейчас. Стандарт C ++ говорит, что вы должны полностью квалифицировать имя в соответствии с 14.6.2 / 3:

В определении шаблона класса или члена шаблона класса, если базовый класс шаблона класса зависит от параметра-шаблона, область действия базового класса не проверяется во время поиска безоговорочного имени либо в точке определения шаблона класса или члена, либо во время создания шаблона класса или члена.

UPD: Наконец-то я нашел дубликат: вот оно .

35 голосов
/ 29 октября 2009

Существует нечто, называемое зависимым и независимым именами для шаблонов.

Если имя зависит от параметра шаблона T, его зависимое имя и другие, которые не зависят от параметра T, являются независимыми именами.

Вот правило: компилятор не смотреть в зависимых базовых классах (например, А) при поиске независимой имена (например, Vec_t). В следствии, компилятор не знает, что они даже существуют, не говоря уже о типах.

Компилятор не может предположить, что Vec_t является типом, пока он не знает T, поскольку существует потенциальная специализация A<T>, где A<T>:: Vec_t - это член данных

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

 typename A<T>::Vec_t v;  ← good

Я рекомендую вам пройти через это https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-types.

Старая (неработающая) ссылка: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.18

7 голосов
/ 29 октября 2009

Поскольку компилятор не уверен, что Vec_t называет тип. Например, A<T> может быть специализированным для T=int до , а не с этим конкретным typedef.

3 голосов
/ 19 сентября 2018

Для полноты, вот как вы могли бы немного смягчить эту неприятность:

  • повторно введите эти типы в производные классы или лучше - как методы -
  • просто импортируйте эти имена в область производного класса с using declaration:

template<typename T>
class A
{
public:
    typedef std::vector<T> Vec_t;
};


template<typename T>
class B : public A<T>
{
public:
    using typename A<T>::Vec_t;
    // .........

private:
    Vec_t v;
};

Это может быть полезно, если у вас есть несколько упоминаний унаследованного typedef в производном классе. Также вам не нужно добавлять typename каждый раз с этим.

2 голосов
/ 29 октября 2009

Вам необходимо явно квалифицировать использование Vec_t, потому что компилятор не знает, откуда взялся Vec_t.

Он не может предполагать ничего о структуре A, поскольку шаблон класса A может быть специализированным. Специализация может включать Vec_t, который не является typedef, или может вообще не включать члена Vec_t.

1 голос
/ 21 февраля 2018

Эта концепция может быть связана с тем, как мы используем std::vector<T>. Например, если у нас есть std::vector<int> Foo. Теперь мы решили использовать любой из его типов членов, скажем, iterator. В этом сценарии мы явно упоминаем

std::vector<int>::iterator foo_iterator;

Аналогично, в вашем случае, чтобы использовать открытый тип члена Vec_t из template <typename T> class A, вам необходимо явно объявить его как

A<T>::Vec_t v;
OR
A<int>::Vec_t int_type;
1 голос
/ 29 октября 2009

Vec_t не является зависимым именем, и компилятор должен знать, что это такое, без создания каких-либо шаблонов (в данном случае это базовый класс). Это действительно ничем не отличается от:

template <class T>
class X
{
    std::string s;
}

Здесь компилятору также необходимо знать о std :: string, даже если X не создан, поскольку имя не зависит от аргумента шаблона T (насколько может предположить компилятор).

В целом, typedefs в базовом классе шаблона кажутся довольно бесполезными для использования в производном классе. Однако typedefs полезны для пользователя.

...