Ответ 1
но это отступление от текста стандарта
Реализации разрешено добавлять аргументы по умолчанию для любой функции не виртуальной библиотеки. Это, похоже, позволяет именно такие трюки SFINAE.
Следуя этому ответу, кажется, что эти конструкторы:
template<class U, class V> pair(pair<U, V>&& p);
template<class U, class V> pair(const pair<U, V>& p);
запрещается участвовать в разрешении перегрузки, когда требуется явное преобразование.
Из С++ 11 (§20.3.2, n3290):
Примечание. Этот конструктор не должен участвовать в разрешении перегрузки, если U неявно конвертируется в first_type, а V неявно конвертируется в second_type.
Предложен интересный метод обхода SFINAE, но это отступает от текста стандарта.
Как совместимая реализация может исключить это из-за разрешения перегрузки, за исключением некоторой специальной внутренней магии компилятора? То есть может ли реализация сделать это, и я могу дублировать ее для моего собственного типа, возможно? Похоже, что это не соответствует этому! Это похмелье от удаления понятий из С++ 11?
Я действительно задавался вопросом об использовании частного конструктора для выполнения части SFINAE и делегирования из конструктора public, но он не похож на то, что делегирование конструктора участвует в SFINAE таким образом, чтобы сделать эту работу.
но это отступление от текста стандарта
Реализации разрешено добавлять аргументы по умолчанию для любой функции не виртуальной библиотеки. Это, похоже, позволяет именно такие трюки SFINAE.
Мне не хватало двух частей информации:
gcc использует это:
template<class _U1, class _U2, class = typename
std::enable_if<std::is_convertible<_U1, _T1>::value
&& std::is_convertible<_U2, _T2>::value>::type>
pair(_U1&& __x, _U2&& __y)
: first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { }
Кажется, что трюк по умолчанию используется для анонимного параметра шаблона class
. Я не видел этого раньше, и эта реализация не использовала это.