Я сам использую метод «указательные точки между элементами», но один способ описать его, который иногда помогает другим, заключается в следующем:
mylist[X:Y]
X - это индекс первый элемент, который вы хотите. Y - это индекс первого элемента, который вы не хотите .
Рассмотрим шаблонный класс 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;
}
};
d
является членом QScopedPointer
. Это не унаследованный член. this->
здесь не требуется.
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>
как известного полного класса иногда и как неизвестный класс несколько раз непоследовательна, ну, вы правы.
Я предполагаю, что это относится к перегруженному использованию процедуры Cleanup (). Передаваемый тип явно управляется типом шаблона T, который, в свою очередь, может контролировать, какая вызывается перегруженная версия Cleanup ().