Распространение '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 ответов:
Я считаю, что этот вопрос является дубликатом, но я не могу найти его сейчас. Стандарт 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;