2009-10-29 3 views
46

Я пытаюсь определить базовый класс, содержащий только typedef.Распространение 'typedef' из основанного на производный класс для 'template'

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; 
+0

Точная копия: HTTP: // stackoverflow.com/questions/1567730/inheritance-and-templates-in-c-why-are-methods-invisible –

+10

Ну, не совсем точный дубликат, так как сообщение, которое вы упоминаете, говорит о методе, в то время как этот говорит о типе. –

+2

typename A :: Vec_t v; Это хорошо. Нет необходимости в там –

ответ

37

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

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

UPD: я нашел дубликат наконец: here it is.

+13

Кстати, мне всегда было так, что мне пришлось «перепечатать» все ... это не приятно, не нравится вообще. –

+13

Кстати, вам не нужны все аргументы шаблона и все, при квалификации. Из-за введенного имени класса достаточно написать 'typename B :: Vec_t' –

7

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

+0

Для 'T' переменной типа' A 'просто объявлен вперед, он не имеет определения. Только 'A ', где 't' является типом (не тип переменной), может быть определен (путем определения определения шаблона или явной специализации). IOW, даже если вы удалили явные и частичные специализации шаблона из C++ (и не изменили ничего другого), это все равно будет неверным. – curiousguy

2

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

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

1

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

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

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

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

+0

Вы имеете в виду 'класс X: T {' здесь? – curiousguy

26

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

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

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

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

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

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

+0

Ваш ответ был единственным ответом, который, как представляется, дал решение в дополнение к объяснению. Спасибо. – Richard

+1

Ссылка была сломана –

+0

Я предлагаю вам +1, если вы сообщите мне, что вы исправили ссылку. –

0

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