Распространение 'typedef' от основанного до производного класса для 'template'

Я пытаюсь определить базовый класс, который содержит только 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 I появляется ошибка, что Vec_t не распознается и мне нужно написать это явно?

typename A<T>::Vec_t v;

7 ответов

Решение

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

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

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

В случае шаблонов есть так называемые зависимые и независимые имена.

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

Вот правило: компилятор не ищет зависимые базовые классы (например, A) при поиске независимых имен (например, 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.

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

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

  • повторно введите эти типы в производные классы или лучше - как в методах -
  • просто импортируйте эти имена в область производного класса с 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 каждый раз с этим.

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

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

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

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

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

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

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

Эта концепция может быть связана с тем, как мы используем 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;
Другие вопросы по тегам