类型安全的模板函数,它接受迭代器

时间:2016-02-24 12:33:38

标签: c++ templates c++11 iterator

我正在编写不同的排序函数,它们需要两个迭代器和排序序列。我想为任何类型的向量实现它们并使它们类型安全,如下所示:

template <typename T>
void itsort(std::vector<T>::iterator begin, std::vector<T>::iterator end)
{
    // code
}

但是由于错误,我只能实现类型不安全的东西:

template <typename T>
void itsort(T begin, T end)
{
    // code
}

如何实现类型安全的模板函数,它需要两个向量迭代器?

PS:目前在比较器中没有必要,所有种类都适用于不同类型的数字。

2 个答案:

答案 0 :(得分:2)

确定某个东西是否是向量的迭代器很难,而且大多没有意义。

矢量迭代器的类型在标准下非常自由。在某些实现中,它们甚至可以是裸指针。

此外,生成迭代器的向量类型可能无法从迭代器中导出。例如,std::vector<int, some_allocator>::iterator可能与std::vector<int>::iterator不同或类型相同。它们都可以是int*,或者它们可以是围绕指针的某个类。它们可以是相同类型或不同类型。 (对于不同的容器类型使用相同类型的技术,如果要查找有关它的讨论,则称为SCARY迭代器。)

通常,您无法确定给定的迭代器是否为矢量迭代器。

如果给定的迭代器不是随机访问迭代器,您可以编写将失败的代码,并推导出类型T。首先,使用一些样板来使iterator_traits的访问权限更加简洁:

namespace iterators {
  template<class It>
  using iterator_category =
    typename std::iterator_traits<It>::iterator_category;

  template<class It>
  using value_type =
    typename std::iterator_traits<It>::value_type;
}

现在我们这样做:

template<class It>
void itsort(It begin, It end)
{
  using T = iterator::value_type<It>;
  using category = iterator::iterator_category<It>;
  static_assert(
    std::is_base_of<std::random_access_iterator_tag, category>::value, "This function only supports random-access iterators"
  );
}

这&#34;迟到失败&#34;,因为错误在重载解析时没有发生(SFINAE),但它会为你检查你的类型。

您还可以访问迭代器的基础值类型。

以SFINAE友好的方式执行此操作很困难,因为iterator_traits并非强制要求SFINAE友好,iterator_traits是确定迭代器特征的强制方法。作为一个具体的例子,void*经常匹配指针的空iterator_traits,但它失败了,因为它不是迭代器。

答案 1 :(得分:1)

似乎你正在寻找这样的东西:

#include <iostream> #include <vector> #include <list> #include <iterator> template< typename T > void itsort(T, T, std::bidirectional_iterator_tag) { std::cout << "itsort called for bidirectional iterator\n"; } template <typename T> void itsort(T, T, std::random_access_iterator_tag) { std::cout << "itsort called for random-access iterator\n"; } template< typename T > void alg(T first, T last) { itsort(first, last, typename std::iterator_traits<T>::iterator_category()); } int main() { std::vector<int> v; alg(v.begin(), v.end()); std::list<int> l; alg(l.begin(), l.end()); }