Я считаю, что clang правильно отклоняет этот код.
Неопределенность, которую обнаруживает Clang, может быть воспроизведена на менее сложном примере:
template<typename T>
class TemplateClass {
public:
void method() {}
template<typename U>
static void static_method(U u) { u.TemplateClass::method(); }
};
struct A {};
struct B {};
int main() {
TemplateClass<A> c;
TemplateClass<B>::static_method(c);
}
Здесь наследование в шаблоне опущено, и для реализации используются два независимых класса. Ошибка, вызванная clang, остается прежней.
Прежде всего, в области действия TemplateClass<T>
имя TemplateClass
относится к TemplateClass<T>
из-за внедрения имени класса. По этой причине статический метод может использовать TemplateClass::method
вместо более явного TemplateClass<T>::method
.
Поиск имени, используемый для интерпретации u.TemplateClass::method
в статическом методе, определен в "3.4.5 Доступ к членам класса [base.lookup.classref]" в C ++ 11 и C ++ 98 стандартов.
Соответствующая часть 3.4.5 / 4:
Если id-выражение в доступе к члену класса является qualid-id в форме
class-name-or-namespace-name::...
[...]
Это тот случай, здесь. id-выражение является частью справа от .
, и в нашем случае это квалифицированное имя TemplateClass::method
.
[...]
имя-класса-или-пространства-имен-имен после оператора .
или ->
ищется в контексте
целое постфиксное выражение и в области видимости объекта выражения.
"Область действия всего постфиксного выражения " - это тело статической функции, и в этой статической функции TemplateClass
относится к TemplateClass<B>
, так как функция является членом этого класса. (мы позвонили TemplateClass<B>::static_method
).
Таким образом, в этой области имя относится к TemplateClass<B>
.
«Выражение объекта» - это часть слева от .
, в нашем случае c
. Класс c
равен TemplateClass<A>
, а в рамках этого класса TemplateClass
относится к TemplateClass<A>
.
Таким образом, в зависимости от области, используемой для поиска, имя относится к другому объекту.
Стандарт теперь гласит:
Если имя найдено в обоих контекстах, имя-класса-или-пространства-имен-имен должно ссылаться на одну и ту же сущность.
Это не так в нашей программе. Программа некорректна, и компилятор должен выдать диагностическое сообщение.
Неопределенность остается прежней, если вы замените B
на TemplateClass<A>
, как используется в вопросе.