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

11
在算法中,我可以通过迭代器直接确定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;
}

输出:

container value type: i
container value type: i
2个回答

17
要使类型iterator成为迭代器,并不需要具有iterator::value_type别名。例如,每个指针都是一个迭代器,即ContiguousIterator。用户可以这样写:
int data[] {1, 2, 3, 4};
// iterators will be of type int*
for_each(std::begin(data), std::end(data));

你的代码接受迭代器并预期能够与此类函数调用一起工作。然而,指针并不是唯一的问题:

std::iterator_traits 是来自 C++98 的非常古老的构造,在那些年代里,你无法使用 decltype() 获取迭代器的 value_type 等信息,因为当时还不存在 decltype。如今,你可以这样编写:

auto value = *it;
// and
using value_type = std::decay_t<decltype(*it)>;

对于一些迭代器,但并非所有迭代器。
要小心了,value_type 可以通过两种方式进行自定义,这会破坏上述代码:
- 您的迭代器可以具有 iterator::value_type 类型别名,std::iterator_traits 将会查找该别名。 - 您可以自己定义 std::iterator_traits 的特化版本。
由于存在这些自定义点,您在访问迭代器的类型信息时必须始终使用 std::iterator_traits。即使在 decltype 或 auto 看起来没问题的情况下,您的代码也可能是不正确的,因为 std::iterator_traits 可能已经针对您正在使用的迭代器进行了特化。
另请参阅:iterator_traits 的设计目的是什么?

9
这个答案的第二部分有一个很好的例子,就是臭名昭著的std::vector&lt;bool&gt;std::iterator_traits&lt;std::vector&lt;bool&gt;::iterator&gt;::value_typebool,但是decltype或者auto会给你一些内部位引用包装类型,几乎肯定不是你想要的。 - Miles Budnek
9
这个答案的第二部分有一个很好的例子,就是臭名昭著的std::vector<bool>std::iterator_traits<std::vector<bool>::iterator>::value_typebool,但是decltype或者auto将会给你一个内部的位引用封装类型,几乎肯定不是你想要的。 - Miles Budnek

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

你能在这里添加一个小例子吗? - Hardik
你能在这里加一个小例子吗? - Hardik
4
@HardikSavsaviya 只需将向量替换为数组,你会在 iter::value_type 处得到一个错误:https://godbolt.org/z/K3o8G8EqY。 - Daniel Langr
4
@HardikSavsaviya 只需将向量替换为数组,您将在iter::value_type处遇到错误:https://godbolt.org/z/K3o8G8EqY。 - Daniel Langr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接