Итератор определенного типа - аргумент функции - Метапрограммирование - PullRequest
0 голосов
/ 29 октября 2019

Я пытаюсь написать функцию, которая принимает (прямой) итератор заданного типа. Было бы очень полезно использовать SFINAE. Я пришел к следующему (не работающему) решению:

template<class ForwardIterator,
    typename std::enable_if<
        std::is_same<typename std::iterator_traits<ForwardIterator>::value_type, int>::value
    >::type
>
    inline void foo(ForwardIterator begin, ForwardIterator end)
{
}

В этом случае foo должен вызываться с std::vector<int>::iterator или просто с помощью необработанных указателей int. Проблема в том, что это не работает, как я ожидал. Компилятор (msvc 2019) всегда жалуется на отсутствие соответствующей перегруженной функции.

Что не так с этим кодом?

1 Ответ

1 голос
/ 29 октября 2019

Причина, по которой это не работает, заключается в том, что если enable_if получает истинное значение, ваше объявление будет преобразовано в

template<class ForwardIterator, void>

Это недопустимый способ объявления шаблона. Если вместо этого он скажет class = void, у него будет безымянный параметр со значением по умолчанию void, и он будет работать.

template<class ForwardIterator,
class = typename std::enable_if<
    std::is_same<typename std::iterator_traits<ForwardIterator>::value_type, int>::value
>::type>

Это, однако, связано с другой проблемой. Значение по умолчанию для параметра шаблона не является частью его подписи. Поэтому, если мы попытаемся добавить перегрузку, где мы заменим int на double, мы получим ошибку из-за того, что две функции шаблона имеют одинаковую сигнатуру.

Чтобы решить эту вторую проблему, вместо этого мы делаем вторуюпараметр не типовой параметр. Это сделает сигнатуры уникальными по отношению друг к другу.

template<class ForwardIterator,
typename std::enable_if<
    std::is_same<typename std::iterator_traits<ForwardIterator>::value_type, int>::value
>::type* = nullptr>

Теперь, если enable_if успешно, мы получим void* параметр не-типа со значением по умолчанию nullptr, и мы можем добавитьПерегрузки с различными требованиями в нашем enable_if, если мы хотим.

SFINAE обычно используется для выбора между различными функциями в зависимости от критериев, если вы хотите ограничить шаблон только, static_assert, скорее всего, лучшеoption.

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

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