Как enable_if помогает выбрать специализации шаблона класса? - PullRequest
0 голосов
/ 29 мая 2020

У меня есть базовая c gr asp SFINAE, и я думаю, что понимаю многие примеры того, как std::enable_if использует его для выбора специализаций шаблонов функций, но мне трудно обернуть голову о том, как это работает для шаблонов классов.

Следующий пример взят из cppreference.com объяснения std::enable_if:

template<class T, class Enable = void>
class A {}; // primary template

template<class T>
class A<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
}; // specialization for floating point types

Мне сложно понять, как использование std::enable_if таким образом помогает выбрать специализацию. (Я не сомневаюсь, что это так.)

Когда компилятор видит объявление типа A<float> specialized;, он увидит два возможных экземпляра шаблона, которые подходят:

  1. "primary template "A<T, Enable>, где T - это тип float, а Enable - это тип void (из-за значения по умолчанию).
  2. Специализация A<T, void>, где T - тип float и void - результат выражения с enable_if.

Разве это не двусмысленно? Оба результата фактически приводят к A<T, void>, так почему выбрана специализация?

В другом случае, например A<int> primary;, параметры компилятора выглядят так:

  1. первичный, A<T, Enable>, где T - это тип int, а Enable - это тип void.
  2. Специализация, A<T, ?>, где T - это тип int а ? означает, что я полностью потерялся. В этом случае условие enable_if ложно, поэтому оно не определяет type, что оставляет вам A<int, typename >. Разве это не синтаксическая ошибка? Даже в лице СФИНАЭ?

Ответы [ 2 ]

1 голос
/ 29 мая 2020

Из ссылки на частичная специализация шаблонов классов:

Когда создается экземпляр шаблона класса или переменной (начиная с C ++ 14), и доступны частичные специализации , компилятор должен решить, будет ли использоваться первичный шаблон или одна из его частичных специализаций.

Если только одна специализация соответствует аргументам шаблона, эта специализация используется

В этом случае, если 2-й аргумент специализации сформирован правильно, он выбран именно потому, что это специализация, а не первичный шаблон.

В случае, если 2-й аргумент шаблона не правильно сформирован, тогда SFINAE срабатывает. В частности:

При замене явно указанного или выведенного типа для параметра шаблона специализация отбрасывается из набора перегрузки вместо того, чтобы вызывать ошибку компиляции .

и

* 1 030 *

Следующие ошибки типа являются ошибками SFINAE:

попытка использовать член типа, где тип не содержит указанный член

Как это делается, т.е. как именно компилятор отбрасывает специализацию вместо того, чтобы выдавать ошибку, не указано; компилятор просто обязан делать правильные вещи.

1 голос
/ 29 мая 2020

Разве это не двусмысленно? Оба результата фактически приводят к A<T, void>, так почему же выбрана специализация?

Нет, специализация более специализированная , чем основной шаблон, потому что для этого требуется, чтобы второй параметр был void (при условии, что условие enable_if истинно), в то время как основной шаблон не ограничивает его.

Специализация, A<T, ?>, где T - это тип int а ? означает, где я полностью потерялся. В этом случае условие enable_if ложно, поэтому оно не определяет тип, что оставляет вам A<int, typename >. Разве это не синтаксическая ошибка? Даже в лице СФИНАЭ?

Точно, второй аргумент в специализации оказывается неверным. Но это «мягкая» ошибка, которая обнаруживается SFINAE и заставляет компилятор отказаться от специализации. (Я не думаю, что компилятор текстуально заменит enable_if_t<...>::type пустой строкой, а затем проанализирует A<int, typename >; более вероятно, что он отбросит специализацию, как только заметит отсутствие ::type в enable_if.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...