Распространение '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;