Подтвердить что ты не робот

Специализация SFINAE и частичного класса

Я использую подходы на основе SFINAE в течение довольно долгого времени, особенно для включения/отключения специализированных специализированных шаблонов классов через std::enable_if.

Я был, таким образом, озадачен, прочитав статью, описывающую предложенную идиому псевдонима /t 21:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf

Раздел 4 посвящен обсуждению действительности идиомы и относится к обсуждению, в котором две стороны спорят о применимости SFINAE в частных специализированных шаблонах классов (с Ричардом Смитом, указывая, что в стандарте отсутствует формулировка о Эта тема). В конце раздела упоминается следующая проблема CWG

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2054

Здесь снова указано, что стандарт явно не разрешает пример, воспроизведенный в выпуске.

Я немного озадачен, потому что мне кажется, что, например, использование enable_if в частичной специализации уже довольно давно является стандартной практикой (см., например, документацию Boost, в которой явно упоминаются частичные специализации).

Неужели я неправильно понимаю пункты в вышеприведенных документах или это действительно серая область?

4b9b3361

Ответ 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, поскольку нигде не будет никакой замены.