Given cbegin (), cend (), why not cfront (), cback (), cfind (), ...?

So, to allow code like

auto vect = ...; auto it = vect.begin(), end = vect.end(); // want const_iterator, getting iterator 

to select the correct overload of begin() and end() , even for containers that do not contain constants, more explicit functions cbegin() / cend() have been added.

Why stop?

Associative containers have a find() method with the same problem. Sequence containers have front() and back() , again with the same problem.

Are these missing explicit invalid versions of const or design versions?

+6
source share
2 answers

The wider API has a cost, even just skipping it when searching for the desired function.

 template<class T> T const as_const(T&& t) noexcept(noexcept(T(std::declval<T>())) { return std::forward<T>(t); } template<class T> T const& as_const(T& t) noexcept { return t; } 

does most of what you want. This would even make cbegin obsolete.

(Changes made to the code above based on n4380, below under TC The code is different, because I think n4380 was a little wrong with T&& .)

+7
source

The goal of cbegin / cend is to solve a specific problem. Consider this code:

 std::vector<int> & v = //... v is a non-const reference // For clarity, I want this iterator to be a const_iterator. // This works because iterator is implicitly convertible to const_iterator std::vector<int>::const_iterator iter = find(v.begin(),v.end(),42); // (1) Now I want to use iter in an algorithm std::find(iter, v.end(), 38); //Error, can not deduce the template parameter for Iter. // (2) This works std::find(iter, const_cast<const std::vector<int> &>(v).end(), 38); // (3) This is the same as (2). std::find(iter, v.cend(), 38); 

The problem is that, because of how the template output rules work, the compiler cannot output the template iterator argument to statement (1), because Container::iterator and Container::const_iterator are (potentially) two completely unrelated types (even if the former is implicitly convertible in the latter).

Statement (2) is not exactly a beautiful line, so we need cend() .

Now front() , back() et similia all return the link. A non-constant reference can always be inferred as const in a template function, i.e.

 template<class T> void f( const T & l, const T & r); int main() { int x; vector<int> v; //This will works even if the return type of front() is int&. f(x, v.front()); } 

Since Container::const_reference requires that the standard be equal to const Container::value_type & , cfront() / cback() do not buy anything for us.


It's worth noting that another container library (looking at you Qt) is implemented using Copy-On-Write.

This means that calling the const function in such a container is potentially much cheaper than calling the equivalent non-envelope version, simply because a non-constant can copy the entire container under the hood.

For this reason, there are many constFunction in their interface in Qt containers, and the user has the right to choose the right one.

+3
source

Source: https://habr.com/ru/post/987919/


All Articles