Лучшее совпадение не найдено ADL после момента создания. Это UB?

Рассмотрим следующий код, в котором расположение перегрузок f вызывает некоторое неинтуитивное поведение. Код компилируется без предупреждений как в Clang 3.4.1, так и в gcc 4.8.

template<typename T>
struct A
{
    static const int value = sizeof(f(T()));
};

struct B
{
};

struct D : B
{
};

char f(B);

// instantiates A<D>, unqualified name lookup finds f(B) via ADL
static_assert(A<D>::value == sizeof(f(B())), ""); // passes

long f(D); // but wait, f(D) would be a better match!

// A<D> is already instantiated, f(D) is not found
static_assert(A<D>::value == sizeof(f(B())), ""); // passes

Стандарт C++11 предполагает, что приведенный выше код вызывает неопределенное поведение:

[Temp.dep.candidate]

Для вызова функции, который зависит от параметра шаблона, функции-кандидаты находятся с использованием обычных правил поиска, за исключением того, что:

  • Для той части поиска, в которой используется поиск по неквалифицированному имени или поиск по квалифицированному имени, обнаруживаются только объявления функций из контекста определения шаблона.
  • Для части поиска, использующей связанные пространства имен, найдены только объявления функций, найденные либо в контексте определения шаблона, либо в контексте создания шаблона.

Если имя функции является безусловным идентификатором, и вызов был бы некорректным или нашел бы лучшее соответствие, если бы поиск в связанных пространствах имен учитывал все объявления функций с внешней связью, введенной в эти пространства имен во всех единицах перевода, а не только с учетом эти объявления, найденные в контекстах определения шаблона и создания экземпляра шаблона, ведут к неопределенному поведению программы.

Вызывает ли приведенный выше код это конкретное неопределенное поведение? Можно ли ожидать качественной реализации, чтобы сообщить о предупреждении?

1 ответ

Решение

Вызывает ли приведенный выше код это конкретное неопределенное поведение?

Да. [Temp.point]/7:

Контекст создания выражения, который зависит от аргументов шаблона, представляет собой набор объявлений с внешней связью, объявленных до момента создания специализации шаблона в той же единице перевода.

Точка инстанции находится сразу после первого static_assert-declaration:

Для […] специализации для […] статического члена данных шаблона класса, если специализация создается неявно, потому что на нее ссылаются из другой специализации шаблона […]. В противном случае точка создания такой специализации сразу же следует за объявлением или определением области пространства имен, которое ссылается на специализацию.

Таким образом, было бы действительно лучшее совпадение, если бы мы рассмотрели второе объявление функции - что мы не смогли, так как оно объявлено после момента создания экземпляра A<D>::value, Согласно правилу, которое вы цитировали, код вызывает неопределенное поведение.
Правило в основном расширяет ODR для поиска зависимых имен в шаблонах.

Можно ли ожидать качественной реализации, чтобы сообщить о предупреждении?

Я бы не стал. Учтите также, что неопределенное поведение возвращается ко времени компиляции; Компилятору разрешено, но не обязательно выдавать предупреждение или сообщение об ошибке, если код вызывает UB. Не ожидайте, что компиляторы всегда будут указывать на недопустимый код.

Другие вопросы по тегам