Код действителен, поэтому msvc и icc неверны.
Поскольку аргумент bar
зависит от типа, имя bar
является зависимым именем и ищется только тогда, когдашаблон OtherFunction
создается, а не когда шаблон определен.
C ++ 17 [temp.dep.candidate] / 1:
Для вызова функции, где Постфиксное выражение является зависимым именем, функции-кандидаты находятся с использованием обычных правил поиска ([basic.lookup.unqual], [basic.lookup.argdep]) за исключением того, что:
Для части поиска, использующей поиск по неквалифицированному имени ([basic.lookup.unqual]), найдены только объявления функций из контекста определения шаблона.
Длячасть поиска с использованием связанных пространств имен ([basic.lookup.argdep]), только объявления функций из контекста определения шаблона или контекста создания шаблона.
Итакпереход к [basic.lookup.argdep] / 3:
Пусть X будет набором поиска, созданным неквалифицированным поиском ([basic.lookup.unqual]), и пусть Y будет набором поиска, созданным зависимым от аргумента поиском (определеноследующее).Если X содержит
- декларацию члена класса или
- декларацию функции блочной области, которая не является using-декларацией или
- объявление, которое не является ни функцией, ни шаблоном функции
, тогда Y пусто.В противном случае Y - это набор объявлений, найденных в пространствах имен, связанных с типами аргументов, как описано ниже.Набор объявлений, найденных при поиске имени, представляет собой объединение X и Y .
[Текущий черновик C ++ 20 переставилформулировки в этих разделах.В частности, правило о включении контекста создания экземпляра для поиска зависимого имени в связанных пространствах имен теперь перечислено в [basic.lookup.argdep] /4.5 и является просто Note в [temp.dep.candidate] .Я не уверен, если причина этого только для ясности, или может иметь какое-то отношение к эффектам модулей.]
X является результатом неквалифицированного поиска имени bar
с учетом только объявлений, видимых из контекста определения шаблона.Но поскольку контекст определения шаблона является самым началом вашей единицы перевода, очевидно, что X пусто.
Поскольку X вообще ничего не содержит, он нене содержит перечисленных элементов, из-за которых Y будет пустым.Таким образом, чтобы определить Y , мы смотрим в пространствах имен, связанных с типами аргументов.Тип аргумента в этом экземпляре - hidden::Foo
, поэтому единственное связанное пространство имен - hidden
, и единственный результат поиска имени - функция hidden::bar
.
::bar
не отображается в этом поиске именипоэтому выражение bar(T{})
не может быть неоднозначным.