Ответ 1
Я хотел бы утверждать, что стандарт не поддерживает SFINAE в частичной специализации из-за дефекта формулировки. Начнем с [temp.class.spec.match]:
Частичная специализация соответствует данному фактическому списку аргументов шаблона, если аргументы шаблона частичная специализация может быть выведена из фактического списка аргументов шаблона (14.8.2).
И, из [temp.deduct], предложение SFINAE:
Если подстановка приводит к недопустимому типу или выражению, тип дедукции не выполняется. Недопустимый тип или выражение тот, который был бы плохо сформирован, с требуемой диагностикой, если он написан с использованием замещенных аргументов. [ Заметка: Если диагностика не требуется, программа по-прежнему плохо сформирована. Проверка доступа выполняется как часть замены обработать. -end note] Только недопустимые типы и выражения в непосредственном контексте тип функции и ее типы параметров шаблона могут привести к ошибке дедукции.
Немного модифицированный пример & dagger; из CWG:
template <class T, class U> struct X {
typedef char member;
};
template<class T> struct X<T,
typename enable_if<(sizeof(T)>sizeof(
float)), float>::type>
{
typedef long long member;
};
int main() {
cout << sizeof(X<char, float>::member);
}
Поиск имени на X
находит первичный, с T == char, U == float
. Мы рассмотрим одну частичную специализацию и посмотрим, соответствует ли она "- это означает, что аргументы шаблона" можно вывести "- то есть:
+-------------+--------+-------------------------------------------------+
| | arg1 arg2 |
+-------------+--------+-------------------------------------------------+
| deduce T in | T | enable_if_t<(sizeof(T) > sizeof(float), float> |
| from | char | float |
+-------------+--------+-------------------------------------------------+
Применяются нормальные правила вычета шаблонов. Второй "аргумент" - это не выводимый контекст, поэтому мы выводим T
как char
. sizeof(char) > sizeof(float)
, является ложным, а enable_if_t<false, float>
является недопустимым типом, поэтому вывод типа должен терпеть неудачу... но отказ дедукции может произойти только
в непосредственном контексте тип функции и ее типы параметров шаблона
и мы не имеем дело с типами типов функций или типов шаблонов функций, мы имеем дело с типами параметров шаблона шаблона. Класс не является функцией, поэтому исключение SFINAE не должно применяться, если мы берем все буквально - и модифицированный пример CWG должен привести к жесткой ошибке.
Тем не менее, дух правила, похоже, больше соответствует следующим:
Только недопустимые типы и выражения в непосредственном контексте процесса вычета могут привести к отказу от вычета.
Я не знаю, в чем причина заключается в том, чтобы специально исключить вычет частичной специализации класса. Кроме того, частичное упорядочение частичных специализаций классов также выглядит как функции. Из [temp.class.order]:
Для двухчастичных частных специализированных спецификаций первая более специализированная, чем вторая, если, учитывая после переписать на два шаблона функций, [...]
Стандарт, таким образом, уже в самом следующем разделе демонстрирует двойственность между частными специализациями шаблонов шаблонов и шаблонами функций. Тот факт, что это относится только к порядку частичного специализации, а не к отказу подстановки при дедукции аргумента частичной специализации, нападает на меня как на дефект.
& dagger; Сам пример был X<double, float>
. Но это на самом деле не демонстрирует и не требует SFINAE, поскольку нигде не будет никакой замены.