Распространение «typedef» из базового в производный класс для «шаблона»
-
10-07-2019 - |
Вопрос
Я пытаюсь определить базовый класс, который содержит только 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;