Почему `this` является зависимым от типа выражением, даже если класс шаблона не имеет базового класса?
Следующий код может быть скомпилирован без ошибок:
template <typename T> struct A {
void f() { this->whatever; } // whatever is not declared before
};
int main() {
A<int> a;
}
И я знаю, что это потому, что this
является зависимым от типа выражением, которое делает поиск имени для whatever
откладывается до тех пор, пока фактический аргумент шаблона не станет известен. Так как функция-член f()
никогда не используется в этом случае, так что нет A<T>::f
существует, и поиск имени для whatever
никогда не выполняется.
я могу понять, что this
зависит от типа, если шаблон класса имеет основанную на типе базу, такую как:
template <typename T> struct B { T whatever; };
template <typename T> struct A : B<T> {
void f() { this->whatever; }
};
int main() {
A<int> a;
}
При разборе определения класса шаблона A
невозможно узнать, какой тип его базы, что делает this->whatever
потенциально законный (B<T>
может иметь член по имени whatever
). Наоборот, я не вижу потенциала, который this->whatever
будет законным в первом примере, как только функция-член f
используется где-то.
Итак, мог this->whatever
быть легальным в некоторых моментах в первом примере? Если нет, есть ли другая причина, this
в этом случае следует рассматривать как зависимое от типа выражение?
3 ответа
Ваш код "неправильно сформирован, диагностика не требуется", потому что никогда не существует действительной специализации для A::f
, На самом деле, спецификация говорит, что this->whatever
не является ни членом неизвестной специализации (потому что не существует зависимого базового класса), ни членом текущего экземпляра (потому что он не объявлен ни в независимом базовом классе, ни в самом шаблоне класса). Кроме того, это делает ваш код недействительным, и опять-таки никакая диагностика не требуется (но разрешена). Это объясняется более подробно на /questions/26644104/gde-i-pochemu-ya-dolzhen-postavit-klyuchevyie-slova-template-i-typename/26644111#26644111
this
зависит от типа, потому что вы еще не знаете значений параметров шаблона в определении. Так, например, SomeOtherTemplate<decltype(*this)>
не может быть решена немедленно, но нужно подождать, пока шаблон класса this
создается (так что вам нужно typename
до SomeOtherTemplate<decltype(*this)>::type
).
Однако только потому, что this
зависит от типа, не означает, что this->whatever
это также. Как описано выше, в спецификации есть инструменты, позволяющие правильно классифицировать это как недействительное, и на самом деле она также не делает this->whatever
зависит от типа. Это говорит
Выражение доступа к члену класса ([expr.ref]) зависит от типа, если выражение ссылается на член текущего экземпляра и тип ссылочного члена является зависимым, или выражение доступа к члену класса относится к члену неизвестного специализация.
Ваш пример может быть упрощен еще больше:
template <typename T> struct A {
void f() { this = 1; }
};
int main() {
A<int> a;
}
Заявление this = 1;
никогда не должен компилироваться, и это не может быть исправлено, даже если A<T>
имеет зависящий от типа базовый класс. Однако компилятор не жалуется, пока функция A<T>::f()
создается экземпляр.
Johannes Schaub - litb уже ответил, что это может быть "не требуется никакой диагностики".
Это правила поиска имен зависимых имен.
$ 14,6/9 Разрешение имени [temp.res]:
При поиске объявления имени, используемого в определении шаблона, для независимых имен используются обычные правила поиска ([basic.lookup.unqual], [basic.lookup.argdep]). Поиск имен, зависящих от параметров шаблона, откладывается до тех пор, пока фактический аргумент шаблона не станет известен ([temp.dep]).
Намерение состоит в том, что информации недостаточно, если имя зависит от параметра шаблона, пока фактический аргумент шаблона не известен. Компилятор не различает тип зависимых имен (формируется this
или другие), не будет проверять детали, как класс имеет зависимый базовый класс или нет. Результат может не измениться, как пример кода, который вы показали, но он просто откладывает поиск имени, пока тип не станет известен, чтобы принять наиболее точное решение.