Шаблон-производный класс базового класса шаблона [дубликат]

Я сам использую метод «указательные точки между элементами», но один способ описать его, который иногда помогает другим, заключается в следующем:

mylist[X:Y]

X - это индекс первый элемент, который вы хотите. Y - это индекс первого элемента, который вы не хотите .

35
задан curiousguy 18 July 2012 в 06:44
поделиться

2 ответа

Ответ на C ++ (общий ответ)

Рассмотрим шаблонный класс Derived с базовым классом шаблона:

template <typename T>
class Base {
public:
    int d;
};

template <typename T>
class Derived : public Base<T> {
    void f () {
        this->d = 0;
    }
};

this имеет тип Derived<T>, тип которая зависит от T. Таким образом, this имеет зависимый тип. Таким образом, this->d делает d зависимым именем. Зависимые имена просматриваются в контексте определения шаблона как не зависящие имена и в контексте экземпляра.

Без this-> имя d будет отображаться только как (/ g8)

Другое решение состоит в том, чтобы объявить d в самом определении шаблона:

template <typename T>
class Derived : public Base<T> {
    using Base::d;
    void f () {
        d = 0;
    }
};

Qanswer (конкретный ответ)

d является членом QScopedPointer . Это не унаследованный член. this-> здесь не требуется.

OTOH, QScopedArrayPointer является классом шаблона, а d является наследуемым членом базового класса шаблона:

template <typename T, typename Cleanup = QScopedPointerArrayDeleter<T> >
class QScopedArrayPointer : public QScopedPointer<T, Cleanup>

, поэтому this-> необходимо здесь :

inline T &operator[](int i)
{
    return this->d[i];
}

Легко видеть, что проще всего поставить this-> повсюду.

Понимать причину

Я думаю, всем пользователям C ++ не ясно, почему имена ищутся в независящих базовых классах, но не в зависимых базовых классах:

class Base0 {
public:
    int nd;
};

template <typename T>
class Derived2 : 
        public Base0, // non-dependent base
        public Base<T> { // dependent base
    void f () {
        nd; // Base0::b
        d; // lookup of "d" finds nothing

        f (this); // lookup of "f" finds nothing
                  // will find "f" later
    }
};

Существует причина, по которой «стандарт говорит так»: причина использования привязки имени в шаблонах.

Шаблоны могут иметь имя, которое связано с поздним, когда экземпляр шаблона создается: например, f в f (this). В точке определения Derived2::f() нет никакой переменной, функции или имени типа f, известных компилятору. Множество известных объектов, которые f может ссылаться, пуст в этой точке. Это не проблема, потому что компилятор знает, что он будет искать f позже как имя функции или имя функции шаблона.

OTOH, компилятор не знает, что делать с d ; это не имя функции. Невозможно выполнить последнее связывание с именами функций без имени.

Теперь все это может показаться элементарным знанием полиморфизма шаблонов времени компиляции. Реальный вопрос: почему нет d, связанного с Base<T>::d во время определения шаблона?

Реальная проблема заключается в том, что во время определения шаблона нет Base<T>::d, поскольку существует не полный тип Base<T> в то время: Base<T> объявлен, но не определен! Вы можете спросить: как насчет этого:

template <typename T>
class Base {
public:
    int d;
};

это похоже на определение полного типа!

Собственно, до создания экземпляра это больше похоже на:

template <typename T>
class Base;

в компилятор. Имя не может быть просмотрено в шаблоне класса! Но только в шаблонной специализации (экземпляре). Шаблон - это фабрика для создания специализированного шаблона, шаблон не является набором специализированных шаблонов. Компилятор может искать d в Base<T> для любого конкретного типа T, но он не может искать d в шаблоне класса Base. Пока не будет определен тип T, Base<T>::d остается абстрактным Base<T>::d; только когда тип T известен, Base<T>::d начинает ссылаться на переменную типа int.

Следствием этого является то, что шаблон класса Derived2 имеет полный базовый класс Base0 ], но неполный (объявленный вперед) базовый класс Base. Только для известного типа T, «шаблонный класс» (специализации шаблона класса) Derived2<T> имеет полные базовые классы, как и любой нормальный класс.

Теперь вы видите, что:

template <typename T>
class Derived : public Base<T> 

на самом деле является шаблоном спецификации базового класса (фабрика для спецификации базового класса), которая следует за разными правилами из спецификации базового класса внутри шаблона.

Примечание. Читатель может иметь заметил, что в конце объяснения я составил несколько фраз.

Это совсем другое: здесь d является квалифицированным именем в Derived<T>, а Derived<T> зависит от того, что T является параметром шаблона. Квалифицированное имя может быть ограничено поздним числом, даже если оно не является именем (называемым).

Еще одно решение:

template <typename T>
class Derived : public Base<T> {
    void f () {
        Derived::d = 0; // qualified name
    }
};

Это эквивалентно.

Если вы считаете, что внутри определения Derived<T> обработка Derived<T> как известного полного класса иногда и как неизвестный класс несколько раз непоследовательна, ну, вы правы.

43
ответ дан T.C. 25 August 2018 в 03:38
поделиться

Я предполагаю, что это относится к перегруженному использованию процедуры Cleanup (). Передаваемый тип явно управляется типом шаблона T, который, в свою очередь, может контролировать, какая вызывается перегруженная версия Cleanup ().

1
ответ дан Brent Arias 25 August 2018 в 03:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: