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

StackOverflow https://stackoverflow.com/questions/1643035

Вопрос

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

Решение

Я считаю, что этот вопрос является дубликатом, но сейчас я не могу его найти. Стандарт 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/ вики / Вопросы / шаблоны # имя nondependent-Lookup-типа .

Старая (неработающая) ссылка: http: // www. parashift.com/c++-faq-lite/templates.html#faq-35.18

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

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

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

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

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

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

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

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

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

Эта концепция может быть связана с тем, как мы используем 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;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top