Why does C++ allows assigning an map iterator to a iterator of a map with different comparator?

Viewed 74

I am confused why the following code compiles.

#include <iostream>
#include <map>

int main()
{
    std::map<int,int, std::less<int>> m {{1,10}, {2,20}};
    std::map<int,int, std::greater<int>>::const_iterator it = m.begin();
    std::cout << it->second << std::endl;
    it++;
    std::cout << it->second << std::endl;
}

I assumed C++ would be "strongly typed" in this regard, and disallow me to assign to an iterator of another map type.

I compiled with C++23 switch, but standard version does not seem to affect it.

note: I presume map iterator does not need to know about comparison since it just needs to know how to go to previous/next and dereference, but still seems weird this compiles.

edit: I see const_iterator is "type erasing" but I would like to know why.

cpp reference:

const_iterator LegacyBidirectionalIterator to const value_type

1 Answers

The C++ standard does not require an iterator's type to be unique for a particular instantiation of a container template. All it says about C::iterator where C is a container is that it is:

iterator type whose value type is T

Different containers impose different iterator requirements, and specific containers have more specific definitions, but with regard to exactly what type it is, this is pretty much it. An implementation can comply with this requirement however it wishes. Iterators into the same template that has a different allocator may have a different type... or it may not (though supporting some of the more esoteric aspects of allocators may require them to have different types). And this is even more the case for template parameters that have nothing to do with iteration.

You cannot rely on these being the same type. But the standard isn't going to deny implementations the ability to optimize code by not having to instantiate multiple types that are completely identical for no reason.

Related