Мне нужен шаблон функции, который принимает два итератора, которые могут быть указателями. Если два аргумента являются итераторами 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.
немного проще, чем в предыдущем ответе, нет зависимости от 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<> Проверка на строгое равенство категорий.
Вот пример с 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