Несоответствия с условным noexcept и перегрузками
у меня есть проблема, которая очень похожа на этой один.
короче говоря, у меня есть magic
метод, который noexcept
если другой метод noexcept
.
странно то, что этот "другой метод" имеет две перегрузки, и компилятор выбирает второй перегрузка для определения magic
noexcept
-Несс.
magic
вызывается позже,первый вызывается перегрузка, но noexcept
мыс magic
остается той же!
вот wandbox ссылке
из того, что я понимаю:
-
noexcept(magic(dummy2{}))
звонки -
noexcept(noexcept(adl_caller(...))
, который возвращается к -
adl_caller(..., priority_tag<0>) noexcept
Сuser_method(dummy2)
не известен компилятору на данный момент.
справедливо, однако, как user_method(dummy2)
называется 3 строки выше?
Это предусмотрено стандартом?
Извините, если я не ясно достаточно.
#include <iostream>
template <unsigned N> struct priority_tag : priority_tag<N - 1> {};
template <> struct priority_tag<0> {};
template <typename T>
auto adl_caller(T t, priority_tag<1>) noexcept(noexcept(user_method(t)))
-> decltype(user_method(t)) {
std::cout << "first adl_caller overload" << std::endl;
user_method(t);
}
// tricky noexcept ...
template <typename T> void adl_caller(T, priority_tag<0>) noexcept {
std::cout << "second adl_caller overload" << std::endl;
}
template <typename T>
void magic(T t) noexcept(noexcept(adl_caller(t, priority_tag<1>{}))) {
adl_caller(t, priority_tag<1>{});
}
struct dummy {};
struct dummy2 {};
// un-commenting this line makes the above call to cout print '0'
// void user_method(dummy2);
void user_method(dummy)
{
// user_method(dummy2) is declared after this point
// this line prints '1', since magic falls back to the second adl_caller overload
std::cout << "noexcept?: " << noexcept(magic(dummy2{})) << std::endl;
std::cout << "dummy method called" << std::endl;
// however, the first adl_caller overload is called here ...
magic(dummy2{});
}
void user_method(dummy2)
{
std::cout << "dummy2 method called" << std::endl;
}
int main()
{
magic(dummy{});
}
1 ответов
специализация шаблона функции [...] мочь иметь несколько точек экземпляров в единице перевода, и в дополнение к пунктам создания экземпляра, описанным выше, для любого такая специализация, которая имеет точку инстанцирования внутри переводческая единица, конец переводческой единицы также считается точка создания экземпляра. [...] Если две разные точки инстанцирования дать шаблон специализация различные значения согласно правило одно-определения, программа плохо сформирована, никакой диагностики требуемый.
сравнить [temp.отдел.кандидат]:
для вызова функции, где постфиксное-выражение - это зависит от имя, функции-кандидаты найдены с использованием обычных правил поиска ([основной.уважать.unqual], [basic.уважать.argdep]) кроме того, что:
для части подстановка с помощью подстановки неквалифицированных имен найдены только объявления функций из контекста определения шаблона.
для части поиска с использованием связанных пространств имен ([basic.уважать.argdep]), только объявления функций в контекст определения шаблона или контекст создания экземпляра шаблона найдены.
Если вызов будет плохо сформирован или найдет лучшее совпадение, поиск в связанном пространства имен рассматривали все функции объявления с внешней связью, введенные в эти пространства имен в все переводческие единицы, а не только с учетом найденных деклараций затем в контекстах определения шаблона и создания экземпляра шаблона программа имеет неопределенное поведение.