Почему `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
следует рассматривать как зависимое от типа выражение в этом случае?
Ответы
Ответ 1
Ваш код "плохо сформирован, не требуется диагностика", потому что для A::f
никогда не существует актуальной специализации. Фактически, спецификация говорит, что this->whatever
не является членом неизвестной специализации (потому что не существует зависимого базового класса), ни членом текущего экземпляра (поскольку он не объявлен в независящем базовом классе, ни в сам шаблон класса). Это, кроме того, делает ваш код недействительным, и снова диагностика не требуется (но разрешена). Это объясняется более подробно на fooobar.com/questions/11848/...
this
зависит от типа, потому что вы еще не знаете значения параметра шаблона в определении. Поэтому, например, SomeOtherTemplate<decltype(*this)>
не может быть разрешен немедленно, но ему нужно подождать, пока не будет создан шаблон класса this
(так что вам нужно typename
до SomeOtherTemplate<decltype(*this)>::type
).
Однако только потому, что this
зависит от типа, это не означает, что this->whatever
также. Как описано выше, спецификация имеет инструменты, чтобы правильно классифицировать это как недействительные, и на самом деле также не делает тип this->whatever
зависимым от типа. В нем говорится:
Выражение доступа к члену класса ([expr.ref]) зависит от типа, если выражение относится к члену текущего экземпляра, а тип ссылочного элемента зависит или выражение доступа к члену класса относится к элементу неизвестной специализации.
Ответ 2
Ваш пример может быть еще более упрощен:
template <typename T> struct A {
void f() { this = 1; }
};
int main() {
A<int> a;
}
Оператор this = 1;
никогда не должен компилироваться и не может быть исправлен, даже если A<T>
имеет базовый класс, зависящий от типа. Однако компилятор не жалуется, пока не будет создана функция A<T>::f()
.
Как Johannes Schaub - litb уже ответил , это может быть ситуация, "не требующая диагностики".
Ответ 3
Это правила поиска имени для зависимых имен.
$14.6/9 Разрешение имени
[Temp.res]:
При поиске декларации имени, используемого в определении шаблона, обычные правила поиска ([basic.lookup.unqual], [basic.lookup.argdep]) используются для не зависимых имен. Поиск имен, зависящих от параметров шаблона, откладывается до тех пор, пока не будет известен фактический аргумент шаблона ([temp.dep]).
Цель состоит в том, что информации недостаточно, если имя зависит от параметра шаблона, пока не будет известен фактический аргумент шаблона. Компилятор не будет различать тип зависимых имен (сформированный this
или другими), не будет проверять детали, как класс имеет зависимый базовый класс или нет. Результат может не измениться, как пример кода, который вы показали, но он просто откладывает поиск имени до тех пор, пока тип не будет известен, чтобы сделать наиболее точное решение.