为什么算法使用 iterator_traits<T>::value_type 而不是 iter::value_type?

Har*_*dik 11 c++ templates iterator iterator-traits

在算法中,我可以value_type通过 直接从迭代器确定iter::value_type。为什么算法会iterator_traits做同样的事情?

#include <iostream>
#include <vector>
#include <iterator>
#include <typeinfo>
using namespace std;

template<typename iter>
void for_each(iter first, iter end)
{
    cout << "container value type: "
         << typeid(typename iter::value_type).name()
         << endl;

    cout << "container value type: "
         << typeid(typename iterator_traits<iter>::value_type).name()
         << endl; 
}

int main()
{
    vector<int> v1;
    for_each(begin(v1), end(v1));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

container value type: i
container value type: i
Run Code Online (Sandbox Code Playgroud)

Jan*_*tke 17

对于要成为迭代器的类型iterator,不需要有别名iterator::value_type。例如,每个指针都是一个迭代器,即ContigeousIterator。用户可能会写:

int data[] {1, 2, 3, 4};
// iterators will be of type int*
for_each(std::begin(data), std::end(data));
Run Code Online (Sandbox Code Playgroud)

您接受迭代器的代码预计可以与此类函数调用一起使用。不过,指针并不是唯一的问题:

std::iterator_traits是 C++98 中一个非常古老的构造,在那时,您无法使用 获取value_type迭代器的之类的信息decltype(),因为decltype它不存在。如今,你可以这样写:

auto value = *it;
// and
using value_type = std::decay_t<decltype(*it)>;
Run Code Online (Sandbox Code Playgroud)

对于某些迭代器,但不是全部。

请注意value_type可以通过两种破坏上述代码的方式进行自定义:

  • 你的迭代器可以有一个iterator::value_type类型别名,它将std::iterator_traits寻找
  • 您可以std::iterator_traits<iterator>自己定义专业

由于存在这些自定义点,因此在访问有关迭代器的类型信息时必须始终使用这些自定义点。std::iterator_traits即使在decltypeauto看起来不错的情况下,您的代码也可能不正确,因为std::iterator_traits它是专门针对您正在使用的迭代器的。


另请参阅:iterator_traits 的设计目的是什么?

  • 这个答案的第二部分的一个很好的例子是臭名昭著的“std::vector&lt;bool&gt;”。`std::iterator_traits&lt;std::vector&lt;bool&gt;::iterator&gt;::value_type` 是 `bool`,但是 `decltype` 或 `auto` 会给你一些内部位引用包装类型,这几乎肯定不是什么你要。 (9认同)

BoP*_*BoP 11

指针是有效的迭代器类型(例如数组),但没有value_type成员。但是,iterator_traits仍然适用于该指针类型。

  • @HardikSavsaviya 只需将向量替换为数组,您就会在 `iter::value_type` 处收到错误:https://godbolt.org/z/K3o8G8EqY。 (4认同)