C++ 使用迭代器的类型安全模板函数

C++ 使用迭代器的类型安全模板函数,c++,templates,c++11,iterator,C++,Templates,C++11,Iterator,我正在编写不同的排序函数,它使用两个迭代器和排序序列。我想为任何类型的向量实现它们,并使它们具有类型安全性,如下所示: template <typename T> void itsort(std::vector<T>::iterator begin, std::vector<T>::iterator end) { // code } 模板 void itsort(std::vector::迭代器开始,std::vector::迭代器结束) { //代

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

template <typename T>
void itsort(std::vector<T>::iterator begin, std::vector<T>::iterator end)
{
    // code
}
模板
void itsort(std::vector::迭代器开始,std::vector::迭代器结束)
{
//代码
}
但由于错误,我只能实现不安全的类型:

template <typename T>
void itsort(T begin, T end)
{
    // code
}
模板
void itsort(T开始,T结束)
{
//代码
}
如何实现使用两个向量迭代器的类型安全模板函数


PS:目前不需要比较器,所有类型的数字都使用不同类型的数字。

确定某个东西是否是向量的迭代器是很困难的,而且大部分是毫无意义的

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

此外,生成迭代器的向量类型可能无法从迭代器中推断。例如,
std::vector::iterator
可能与
std::vector::iterator
不同或相同类型。它们可以是
int*
,也可以是围绕指针的类。它们可以是相同的类型,也可以是不同的类型。(如果您想找到关于同一类型的讨论,那么将同一类型用于不同容器类型的技术称为可怕的迭代器)

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

如果给定的迭代器不是随机访问迭代器,则可以编写失败的代码,并推断类型
T
。首先,使用一点样板文件,使对
迭代器特性的访问不那么冗长:

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;
}
命名空间迭代器{
模板
使用迭代器=
typename std::iterator_traits::iterator_category;
模板
使用值类型=
类型名称std::迭代器特征::值类型;
}
现在我们这样做:

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"
  );
}
模板
void itsort(它开始,它结束)
{
使用T=iterator::value\u类型;
使用category=iterator::iterator\u category;
静态断言(
std::is_base_of::value,“此函数仅支持随机访问迭代器”
);
}
这种“延迟失败”,即在重载解析(SFINAE)时不会发生错误,但它会为您检查类型

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


以SFINAE友好的方式这样做是困难的,因为
iterator\u traits
不是SFINAE友好的强制方式,而
iterator\u traits
是确定迭代器特性的强制方式。作为一个具体的例子,
void*
经常匹配指针的空的
迭代器,但是它失败了,因为它不是迭代器。

确定某个东西是否是向量的迭代器是困难的,而且大部分是无意义的

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

此外,生成迭代器的向量类型可能无法从迭代器中推断。例如,
std::vector::iterator
可能与
std::vector::iterator
不同或相同类型。它们可以是
int*
,也可以是围绕指针的类。它们可以是相同的类型,也可以是不同的类型。(如果您想找到关于同一类型的讨论,那么将同一类型用于不同容器类型的技术称为可怕的迭代器)

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

如果给定的迭代器不是随机访问迭代器,则可以编写失败的代码,并推断类型
T
。首先,使用一点样板文件,使对
迭代器特性的访问不那么冗长:

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;
}
命名空间迭代器{
模板
使用迭代器=
typename std::iterator_traits::iterator_category;
模板
使用值类型=
类型名称std::迭代器特征::值类型;
}
现在我们这样做:

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"
  );
}
模板
void itsort(它开始,它结束)
{
使用T=iterator::value\u类型;
使用category=iterator::iterator\u category;
静态断言(
std::is_base_of::value,“此函数仅支持随机访问迭代器”
);
}
这种“延迟失败”,即在重载解析(SFINAE)时不会发生错误,但它会为您检查类型

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


以SFINAE友好的方式这样做是困难的,因为
iterator\u traits
不是SFINAE友好的强制方式,而
iterator\u traits
是确定迭代器特性的强制方式。作为一个具体的例子,
void*
通常与指针的空
迭代器匹配,但是它失败了,因为它不是迭代器。

似乎您正在寻找类似的东西:

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

#包括
#包括
#包括
#包括
模板
void itsort(T,T,std::双向迭代器标记)
{

std::cout似乎您正在寻找这样的东西:

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

#包括
#包括
#包括
#包括
模板
void itsort(T,T,std::双向迭代器标记)
{

std::不能使用
typename std::vector::iterator
。尝试std::vector::iterator前面的typename即使使用
typename
,它将是一个不可推断的上下文,并且您必须在调用站点提供
。为了确保类型安全,您将使用某种
范围
顺便说一句。@juanchopanza使用
typename
对于OP发布的问题,这是一个糟糕的解决方案。使用
typename std::vector::iterator
。在std::vector::iterator前面尝试typename即使使用
typename
,它将是一个不可推断的上下文,并且您必须在调用站点提供
。为了确保类型安全,您将使用某种