Подтвердить что ты не робот

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

Ответ 1

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

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

UPD: Я нашел дубликат окончательно: здесь он.

Ответ 2

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

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

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

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

Таким образом, решение - это использование typename

 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

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

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

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

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

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

Ответ 7

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