New std::map::erase() signature C++17 - c++

According to this answer, an iterator must be implicitly convertible to const_iterator. Since that is true, as we can see happening in insert_or_assign(), then why in C++17 was a new signature added to std::map::erase()?
In C++11, we have iterator erase( const_iterator pos );
In C++17, we now have iterator erase( iterator pos );
Wasn't the C++11 signature good enough to receive iterator and const_iterator?

There's a potential ambiguity with erase(const key_type& key) when you pass an iterator. Consider the case where the key_type is something like std::any.

Related

(C++) A question about "insert" function in vector

https://en.cppreference.com/w/cpp/container/vector/insert
Cppreference shows: iterator insert( const_iterator pos, const T& value ); and four other overloads.
But why the parameter is const_iterator but not iterator?
Whether or not the iterator is const doesn't matter, since the container is the thing being modified (and insert is not a const-qualified member function), not the passed in iterator.
And this just makes it easier to use. A non-const iterator is convertible to a const_iterator (but not the other way around) so you can still easily use an iterator.
A somewhat relevant paper: https://wg21.link/N2350

non-const find() in std::unordered_set

Why for there is non-const find() in std::unordered_set()?
iterator find( const Key& key );
const_iterator find( const Key& key ) const;
iterator is the same as const_iterator, why there is non-const version of find()?
http://en.cppreference.com/w/cpp/container/unordered_set/find
iterator is the same as const_iterator, why there is non-const version of find()?
Because iterator is not mandatory the same as const_iterator, as stated in documentation:
The member types iterator and const_iterator may be aliases to the same type. Since iterator is convertible to const_iterator, const_iterator should be used in function parameter lists to avoid violations of the One Definition Rule.
emphasis is mine. Since they are not mandatory the same some generic code can depend on particular type of iterator returned by find() and it should be consistent with other containers.

Classification of std::vector's iterators

In the description of std::vector on cppreference (http://en.cppreference.com/w/cpp/container/vector/begin), I miss the categorization of the iterator (according to http://www.cplusplus.com/reference/iterator/) that is returned by the begin() function (the same applies for the iterator returned by end()).
Does cppreference not have to state which category of iterator is returned by begin() so that the user knows the iterator's functionality?
Currently, for me, it remains unclear which functionality std::vector's iterators provide.
Look at the main desciption of std::vector under the section Member types:
iterator RandomAccessIterator
const_iterator Constant random access iterator
reverse_iterator std::reverse_iterator<iterator>
const_reverse_iterator std::reverse_iterator<const_iterator>
std::vector uses RandomAccessIterator
A RandomAccessIterator is a BidirectionalIterator that can be moved to
point to any element in constant time. A pointer to an element of an
array satisfies all requirements of RandomAccessIterator
...
On the cppreference page for std::vector you will find:
Member types
============
...
iterator RandomAccessIterator
From here http://en.cppreference.com/w/cpp/container/vector you can see that a vector's iterators model the RandomAccessIterator concept: http://en.cppreference.com/w/cpp/concept/RandomAccessIterator
std::vector::begin() returns a std::vector::iterator (or const_iterator)
std::begin(x) returns the result of x.begin()
Therefore std::begin(std::vector<...>) will return a random access iterator.

Why const_iterator could be used with std::map::erase

I was under the impression one cant use erase on a const iterator. Check this code.
Why does the below code compile (C++11, gcc)?
long getMax(const bool get_new)
{
long max_val=0;
TO now=getNow();
map<TO, long>& m=get_new?m_new:m_old;
for(auto it=m.cbegin(); it !=m.cend())
{
if(now.compareTime((*it).first)<lookback)
{
max_val=max(max_val,
(*it).second);
++it;
}
else
{
it=m.erase(it);
}
}
return max_val;
}
The map itself is not constant, but my understanding is that the const iterator should make this fail.
The behavior has changed from C++11; std::map::erase takes const_iterator as its parameter.
void erase( iterator pos ); // (until C++11)
iterator erase( const_iterator pos ); // (since C++11)
iterator erase( iterator pos ); // (since C++17)
For std::map::erase, the passed iterator is just used as the position where the element would be deleted, not for modifying the element through it. That means const_iterator would be fine. Before C++11, the support for const_iterator was not very good, but the situation has changed from C++11. You should use const_iterator instead of iterator when possible now.
Positions are independent of the constness of their access. It was (is?) quite common that functions doing a search return const_iterator because they actually do not change the container at all. However, it is desirable to use the obtained position for mutations of the sequences, e.g., to insert() an element at the corresponding position or to erase() the located element. As a result, the container where extended to support use of const_iterator with mutating operations.
It seems the relevant paper is N2350. I'm not sure if this paper is the latest version.

multimap::erase() standard behaviour?

I've been comparing documentation for the multimap::erase function. After checking out Josuttis and cplusplus.com, it looks as though there are three overloads:
void erase(iterator position);
size_type erase(const key_type& x);
void erase(iterator first, iterator last);
However, the MSDN documentaion appears to suggest three slightly different overloads:
iterator erase(iterator where);
iterator erase(iterator first, iterator last);
bool erase(key_type key)
Why the differences? Am I just being a bit slow and looking at the wrong docs, or has the standard moved on and I'm just looking at outdated documentation?
The correct overloads are (from http://en.cppreference.com/w/cpp/container/multimap/erase):
void erase( iterator position ); (until C++11)
iterator erase( const_iterator position ); (since C++11)
void erase( iterator first, iterator last ); (until C++11)
iterator erase( const_iterator first, const_iterator last ); (since C++11)
size_type erase( const key_type& key );
The cplusplus.com documentation is out of date; the Microsoft documentation is simply incorrect (overloads possibly copied erroneously from map documentation); it does say later that the third form returns a count of the number of elements removed so clearly cannot return bool.
According to this, it actually depends on the version of the standard your STL is conforming to.
What you read on MSDN is C++ 11, and on cplusplus.com it's for older C++.
The link from MSDN appears to document a library that wraps the STL for use in CLR. The first code snippet is correct and is the same as that in C++03 standard, and only differs from the C++11 standard in the iterators are const. From section 23.4.5.1 Class template multimap overview of the C++11 standard:
iterator erase(const_iterator position);
size_type erase(const key_type& x);
iterator erase(const_iterator first, const_iterator last);
The MSDN documentation you linked to is the STL/CLR version. That's a subset of the Standard C++ Library for use with C++ and the .NET Framework common language runtime (CLR).
The correct MSDN C++ documentation for std::multimap::erase is here.