У меня есть функция шаблона, которая должна быть специализированной для итераторов. Итак, что я сделал по принципу:
template <typename T>
void function2(T whatever, typename std::iterator_traits<T>::pointer) // ... iterator
template <typename T>
void function2(T whatever, ...) // ... non-iterator
template <typename T>
void function(T whatever) {
function2(whatever, NULL);
}
И я врезался в стену, потому что стандартная библиотека Microsoft специализируется std::iterator_traits
для всех числовых типов (bool
, char
, int
, float
…). И делает это так, чтобы reference
а также pointer
не являютсяvoid
несмотря на то, что ни operator*
ни operator->
можно назвать по этим типам.
Хорошо, я могу проверить std::iterator_traits<T>::category
производный std::input_iterator
(на самом деле я думаю, std::forward_iterator
более уместно в моем случае) за счет некоторого более сложного шаблонного механизма.
Однако мне было бы интересно узнать:
iterator_traits
для типов, которые не соответствуют концепции итератора (даже для выходных итераторов требуется как минимум одинарный operator*
Ни один из этих типов не имеет ни одного.std::iterator_traits<T>::pointer
всегда существует, но не определено, и это приводит к ошибке, а не к SFINAE.Другие функции [res.on.functions]
[…]2 В частности, эффекты не определены в следующих случаях:
- для типов, используемых в качестве аргументов шаблона при создании экземпляра компонента шаблона, если операции над
тип не реализует семантику применимого подпункта Требования
Для того, чтобы использовать iterator_traits<T>
, T
должен быть итератором. Если это не так, поведение не определено. Вы не можете определить, является ли тип T
является итератором во время компиляции. Это даже теоретически невозможно, так как типу разрешено поддерживать те же операторы и определения типов, что и итераторам, так что общий тип реализации iterator_traits<T>
может быть создан без каких-либо ошибок или предупреждений, но с совершенно другим значением.
Подумав об этом, так как ваш комментарий уточняет, что разумное предположение достаточно хорошо, я думаю, что вам лучше использовать SFINAE и enable_if
обнаружить основные операции (унарный *
и префикс ++
), с помощью std::iterator_traits<T>::pointer
только если эти условия соблюдены.
Других решений пока нет …