Reputation: 76346
I have a template function, that needs to be specialized for iterators. So what I did was along the lines of:
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);
}
And I've hit a wall, because Microsoft standard library specializes std::iterator_traits
for all numeric types (bool
, char
, int
, float
…). And it does it so that reference
and pointer
are non-void
, despite the fact that neither operator*
nor operator->
can be called on those types.
Ok, I can checki the std::iterator_traits<T>::category
derives std::input_iterator
(actually I think std::forward_iterator
is more appropriate in my case) at the cost of some more complex template machinery.
I would however be interested in knowing:
iterator_traits
for types, that don't conform to the iterator concept (even output iterators need at least unary operator*
, none of these types have one.std::iterator_traits<T>::pointer
always exists, but is undefined and that leads to error rather than SFINAE.Upvotes: 1
Views: 122
Reputation:
Other functions [res.on.functions]
[...]
2 In particular, the effects are undefined in the following cases:
- for types used as template arguments when instantiating a template component, if the operations on the type do not implement the semantics of the applicable Requirements subclause
In order to use iterator_traits<T>
, T
must be an iterator. If it isn't, the behaviour is undefined. You cannot detect whether a type T
is an iterator at compile time. It is not even theoretically possible, since a type is allowed to support the same operators and typedefs as iterators, so that an implementation's generic iterator_traits<T>
can be instantiated without any error or warning message, but with a completely different meaning.
Thinking about it, since your comment clarifies that a reasonable guess is good enough, I think you're best off using SFINAE and enable_if
to detect core operations (unary *
and prefix ++
), using std::iterator_traits<T>::pointer
only if those conditions are met.
Upvotes: 2