Ответ 1
Вся суть вопроса: ADL:
N3797 - [basic.lookup.argdep]
Когда постфиксное выражение в вызове функции (5.2.2) является неквалифицированным-id, другие пространства имен не считаются во время обычного неквалифицированного поиска (3.4.1), и в этих пространствах имен пространство имен могут быть найдены другие функции или объявления шаблонов функций (11.3), которые не отображаются в других местах.
следующее:
Для каждого типа аргумента T в вызове функции существует набор из нулевых или более связанных пространств имен и a набор нулевых или более связанных классов. [...] Наборы пространства имен и классы определяются следующим образом:
- Если T - тип класса [..], его ассоциированные классы:... furthemore, если T является специализацией шаблона класса, его связанные пространства имен и классы также включают: пространства имен и классы, связанные с типы аргументов шаблона, предоставленные для параметров типа шаблона
D<A>
является ассоциированным классом и, следовательно, в списке, ожидающем его поворота.
Теперь для интересной части [temp.inst]/1
Если спецификация шаблона класса явно не была создана (14.7.2) или явно специализирована (14.7.3), специализация шаблона класса неявно создается [...] , когда полнота типа класса влияет на семантику программы
Можно подумать, что полнота типа D<A>
вообще не влияет на семантику этой программы, однако [basic.lookup.argdep]/4 говорит:
При рассмотрении связанного пространства имен поиск выполняется так же, как и поиск, выполняемый, когда соответствующее пространство имен используется как определитель (3.4.3.2) кроме того:
[...] Любые функции имени пространства имен или шаблоны функций друзей, объявленные в связанных классах, видны в их соответствующих пространства имен, даже если они не видны во время обычного поиска (11.3)
то есть. полнота типа класса фактически влияет на объявления друзей → полнота типа класса влияет на семантику программы. Это также причина, по которой работает ваш второй образец.
TL; DR D<A>
создается.
Последний интересный момент касается того, почему ADL запускается в первую очередь для
u = v; // Triggers ADL
u.operator=(v); // Doesn't trigger ADL
В §13.3.1.2/2 указывается, что не может быть нечлена operator=
(кроме встроенных). Присоедините это к [over.match.oper]/2:
Набор кандидатов, не являющихся членами, является результатом неквалифицированного поиска оператора @в контексте выражения в соответствии с обычными правилами поиска имен в неквалифицированных вызовах функций (3.4.2) за исключением того, что все функции-члены игнорируются.
и логический вывод: нет смысла выполнять поиск ADL, если в таблице 11 нет формы, отличной от члена. Однако [temp.inst] p7 расслабляет это:
Если процесс разрешения перегрузки может определить правильную функцию для вызова без создания экземпляра определения шаблона класса, не указано, действительно ли это создание.
и что причина, по которой clang инициировала весь процесс ADL -> implicit instantiation
, в первую очередь.
Начиная с r218330 (на момент написания этого, это было сделано несколько минут назад), это поведение было изменено, чтобы не выполнять ADL для operator=
вообще.
Ссылки
- r218330
- источники clang/Sema module
- cfe-dev
- N3797
Спасибо Ричарду Смиту и Дэвиду Блейки за то, что помогли мне понять это.