我需要一个函数模板,它接受两个可能是指针的迭代器。如果两个参数是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。
答案 0 :(得分:3)
以下是基于迭代器标记的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的评论,如果我们使用std::iterator_traits,我们可以摆脱指针的专业化。然后typename T::iterator_category
部分变为
typename std::iterator_traits<T>::iterator_category
答案 1 :(得分:2)
比上一个答案简单一点,不依赖于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;
}
该解决方案还支持从std :: random_access_iterator_tag或std :: bidirectional_iterator_tag派生的其他iterator_categories(如果有的话),而std :: same&lt;&gt;检查严格的类别平等。