迭代器是否需要按照标准包含来自容器的任何类型信息?

Does iterator need to include any type information from the container by the standard?

今天我遇到了 问题,开始怀疑 gcc/clang 和 Visual Studio 之间的不一致。

这个问题本身很笼统,但我仍然想了解 - 标准是否对迭代器类型是否应该包含任何容器特定类型信息强加了任何规则。考虑这个片段:

#include <unordered_map>
#include <iostream>

struct hash1
{
    size_t operator()(int key) const
    {
        return key;
    }
};

struct hash2
{
    size_t operator()(int key) const
    {
        return key + 1;
    }

};

int main(int argc, char** argv)
{
    std::unordered_map<int, int, hash1> map1;
    map1[1] = 1;
    std::unordered_map<int, int, hash2> map2;
    map2[1] = 1;
    std::unordered_map<int, int, hash2>::iterator it1 = map1.find(1);
    std::unordered_map<int, int, hash2>::iterator it2 = map2.find(1);
    if (it1 == it2) // Visual Studio 2015 Gives an assertion on iterator type inequality
    {
        std::cout << "equal";
    }
    else
    {
        std::cout << "not equal";
    }
}

所以在 Visual Studio 中 std::unordered_set 迭代器类型只是一个 std::list 迭代器,它当然不知道任何关于散列函数类型的信息,因此我可以执行赋值,然而,相等运算符给出一个断言,因为它在内部比较容器。 GCC/clang 另一方面也忽略类型不兼容但也没有 运行 时间 warnings/errors.

关于这个主题,标准是怎么说的?

标准对此没有任何说明。它指定类型 std::unorderd_map<K, V, H, E, A>::iterator 必须支持的操作。从 std::unorderd_map<K, V, H1, E, A>::iterator 构造不是其中之一(因为 H1 不同于 H)。因此,该标准对编译器必须如何处理包含此类结构的程序没有任何要求。所以就标准而言,GCC 和 VS 都可以。

一对迭代器描述了一个值序列。如果您尝试使用两个不指向同一序列元素的迭代器执行某些操作,则您的程序的行为是未定义的,即,标准不会对程序的操作施加任何要求。

请注意,上一段未在任何地方使用 "container" 一词。容器是创建序列的一种方式,但不是唯一的方式。所以,不,没有要求迭代器知道容器,因为迭代器与容器没有内在联系。