Должен ли этот вызов функции быть неоднозначным? - PullRequest
6 голосов
/ 08 июня 2019

Я наткнулся на это на днях и не могу понять, какой ответ правильный или приемлемы оба.

В частности, я имею в виду вызов bar (T {}) в OtherFunction.Судя по тому, что я смог протестировать в проводнике компилятора, решение кажется разделенным.msvc и icc согласны с тем, что в то время как gcc и clang компилируют код без проблем, это неоднозначно.

Функциональная панель внутри скрытого пространства имен становится видимой через поиск, зависящий от аргументов.Кроме того, msvc / icc рассматривает объявление bar в глобальном пространстве имен в качестве кандидата, а gcc / clang - нет.Кажется, что объявление в глобальном пространстве имен не должно рассматриваться, так как оно объявлено после вызова bar (T {}), но я не уверен, правильно ли я читаю правила поиска неквалифицированных имен или стандартнеоднозначно в этом отношении.

https://godbolt.org/z/HAS-Cv

РЕДАКТИРОВАТЬ: похоже, msvc исправил это, пока используется / permissive- опция (https://devblogs.microsoft.com/cppblog/two-phase-name-lookup-support-comes-to-msvc/)

template <typename T>
inline void OtherFunction () {
    bar(T{});
}

namespace hidden {
    struct Foo {};
    inline void bar (Foo foo) {}
}

inline void bar (hidden::Foo foo) {}

void Function () {
    OtherFunction<hidden::Foo>();
}

Ответы [ 2 ]

3 голосов
/ 08 июня 2019

Gcc и Clang верны.Глобальный bar, определенный после определения OtherFunction, не может быть найден с помощью name lookup ;в то время как hidden::bar может быть найдено ADL .

(выделение мое)

Для зависимого имени, используемого в определении шаблона, поиск откладывается доаргументы шаблона известны, и в это время ADL проверяет объявления функций with external linkage (until C++11), видимые из контекста определения шаблона, а также в контексте создания шаблона, в то время как поиск без ADL проверяет только объявления функций with external linkage (until C++11), видимые изконтекст определения шаблона (другими словами, , добавление нового объявления функции после определения шаблона не делает его видимым, кроме как через ADL ).

2 голосов
/ 08 июня 2019

Код действителен, поэтому 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{}) не может быть неоднозначным.

...