Распространение 'typedef' из базового в производный класс для 'шаблона'


Я пытаюсь определить базовый класс,который содержит только 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 52

7 ответов:

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

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

UPD: я нашел дубликат, наконец: здесь.

есть что-то под названием зависимый и поиск независимых имена в случае шаблонов.

если имя зависит от параметра шаблона 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++-часто задаваемые вопросы-лайт/шаблоны.сообщение: чаво-35.18

потому что компилятор не уверен, что 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 полезны для пользователя.

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

  • re-typedef эти типы в производных классах, или лучше-как с методы -
  • просто импортируйте эти имена в область производного класса с помощью 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::Vec_t;
    // .........

private:
    Vec_t v;
};

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

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