non-const find() in std::unordered_set - c++

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.

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

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

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.

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.

map::find with a type that's comparable but not convertible to key_type

std::map::find accepts const key_type& as an argument. This way it requires the argument to be convertible to key_type. That seems an oversight to me because the argument doesn't have to be convertible to key_type, it only has to be comparable to it.
I can make an arbitrary type comparable by defining two operator< overloads:
struct A;
bool operator<(const key_type&, const A&);
bool operator<(const A&, const key_type&);
map::find should itself be a template. But it's not. So now that I'm done whining I can ask the actual question: is there a way to easily work around this and search among map keys by a comparable but not convertible value?
My understanding is I could use std::find_if, but that would be linear search instead of binary search (O(n) instead of O(Log(N))). Naturally, I don't want to implement binary search by hand.
Since C++14, map::find is in fact a template and works exactly as you desire (at least when the given Compare::is_transparent condition described below is satisfied).
From cppreference:
std::map::find
C++ Containers library std::map
iterator find(const Key& key );
(1)
const_iterator find( const Key& key ) const;
(2)
template< class K > iterator find( const K& x );
(3) (since
C++14)
template< class K > const_iterator find( const K& x ) const;
(4) (since C++14)
1,2) Finds an element with key equivalent to key.
3,4) Finds an element with key that compares equivalent to the value
x. This overload only participates in overload resolution if the
qualified-id Compare::is_transparent is valid and denotes a type. It
allows calling this function without constructing an instance of Key