Ivan Kush
Ivan Kush

Reputation: 3157

C++ template specialization for iterators

I'd like to swap 2 values, pointed by iterators. So I want to specialize template function for taking iterators. Could you tell, please, how could I do this?

Function for non-iterators:

template <typename T>
void exch(T &a, T &b)
{
    T c( std::move(a) );
    a = std::move(b);
    b = std::move(c);   
}

Function for iterators:

template <typename It>
void exch(It &a, It &b)
{
    auto c( std::move(*a) );
    *a = std::move(*b);
    *b = std::move(c);   
}

Of course, with 2 functions I get an error:

/projects/DFSTL/main.cpp:17:6: error: redefinition of ‘template void exch(It&, It&)’

Upvotes: 0

Views: 497

Answers (2)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275280

I would advise against doing this -- swapping a and b, and swapping the things indirectly referred to by a and b, is a tempting thing to overload. But you end up getting really strange behavior if you do that.

If you must, the first step would involve writing your own is_iterator traits class. This can be done through various methods. One that works on some compilers is to use SFINAE resolution of std::iterator_traits<It>::iterator_category, and check if input_iterator_tag or output_iterator_tag is a base of that type.

You do usually need to detect void* and cv variants. This is still implementation defined behavior, as std::iterator_traits on a non-iterator generates implementation defined results.

The more complex way is to examine each of the type axioms of iterators and test them, and if all pass say it is an iterator.

Once you have is_iterator<T>, you can use SFINAE:

template <class T, class=std::enable_if_t< !is_iterator<std::decay_t<T>>{} >>
void exch(T &a, T &b) {
  using std::swap;
  swap(a,b);
}

Function for iterators:

template <class It, class=std::enable_if_t< is_iterator<std::decay_t<It>>{} >>
void exch(It a, It b) {
  using std::iter_swap;
  iter_swap(a,b);
}

note that I called swap and iter_swap in an ADL-enabled context with std:: lookup rather than manually implementing it. This allows types that specialize their own swap in their enclosing namespace to automatically get their more optimal solution.

Upvotes: 2

moosingin3space
moosingin3space

Reputation: 326

Both those template functions look identical to the compiler. That's why you get the compiler error.

Have you tried using this function: std::swap()?

It looks like it does what you want - and has been specialized for all STL container types for which a swap makes sense.

Upvotes: 2

Related Questions