Шаблон функции, принимающий только двунаправленный итератор или указатель

Мне нужен шаблон функции, который принимает два итератора, которые могут быть указателями. Если два аргумента являются итераторами random_access, я хочу, чтобы возвращаемый тип был объектом

std::iterator<random_access_iterator_tag, ...> тип

еще

std::iterator<bidirectional_iterator_tag, ...> тип.

Я также хочу, чтобы код отказался
компиляция, если аргументы не являются ни двунаправленным итератором, ни указателем. Я не могу зависеть от сторонних библиотек, например Увеличение

Не могли бы вы помочь мне с сигнатурой этой функции, чтобы она принимала двунаправленные итераторы, а также указатели, но не говорила input_iterator, output_iterator, forward_iterators.

Одно частичное решение, которое я могу придумать, заключается в следующем

template<class T>
T foo( T iter1, T iter2) {
const T tmp1 = reverse_iterator<T>(iter1);
const T tmp2 = reverse_iterator<T>(iter2);
// do something
}

Идея состоит в том, что, если он не является двунаправленным, компилятор не позволит мне создать из него reverse_iterator.

4

Решение

немного проще, чем в предыдущем ответе, нет зависимости от std :: enable_if:

namespace detail
{
template<class T>
T do_foo(T iter1, T iter2, std::random_access_iterator_tag t)
{
cout << "do_foo random_access" << endl;
return iter1;
}
template<class T>
T do_foo(T iter1, T iter2, std::bidirectional_iterator_tag t)
{
cout << "do_foo bidirectional" << endl;
return iter1;
}

}
template<class T>
void foo(T iter1, T iter2)
{
typename std::iterator_traits<T>::iterator_category t;
detail::do_foo(iter1, iter2, t);
}

int main (int argc, const char * argv[])
{
std::vector<int> v;
foo(v.begin(), v.end());
std::list<int> l;
foo(l.begin(), l.end());
return 0;
}

Решение также поддерживает другие iterator_categories, полученные из std :: random_access_iterator_tag или std :: bidirectional_iterator_tag (если они есть), тогда как std :: same<> Проверка на строгое равенство категорий.

2

Другие решения

Вот пример с enable_if на основе тегов итератора. Замена завершается неудачно, если у данного T нет iterator_category typedef и перегрузка не учитывается при разрешении перегрузки.

Поскольку вы не можете использовать C ++ 11, см. Справочные страницы для enable_if а также is_same чтобы увидеть, как вы можете реализовать это самостоятельно.

#include <iterator>
#include <type_traits>
#include <iostream>
#include <vector>
#include <list>

template<typename T>
typename
std::enable_if<
std::is_same<
typename T::iterator_category,
std::bidirectional_iterator_tag
>::value,
T
>::type
foo(T it)
{
std::cout << "bidirectional\n";
return it;
}

template<typename T>
typename
std::enable_if<
std::is_same<
typename T::iterator_category,
std::random_access_iterator_tag
>::value,
T
>::type
foo(T it)
{
std::cout << "random access\n";
return it;
}

// specialization for pointers

template<typename T>
T* foo(T* it)
{
std::cout << "pointer\n";
return it;
}

int main()
{
std::list<int>::iterator it1;
std::vector<int>::iterator it2;
int* it3;
std::istream_iterator<int> it4;
foo(it1);
foo(it2);
foo(it3);
//foo(it4); // this one doesn't compile, it4 is an input iterator
}

Живой пример.

Согласно комментарию @ JonathanWakely, мы можем избавиться от специализации для указателей, если будем использовать СТД :: iterator_traits. typename T::iterator_category часть становится

typename std::iterator_traits<T>::iterator_category
3

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector