In maximally generic code, prefer non-member versions of begin
, end
, rbegin
, etc., over their member function counterparts.
In C++98, using const
whenever it’s meaningful wasn’t practical: it wasn’t that easy to create them, and once we had one, the ways we could use it were limited. For example:
|
|
The code above search for the first occurrence of 1983 (the year “C++” replaced “C with Classes”), then insert the value 1998 (first ISO C++ Standard was adopted) at that location. If no 1983 found, insert at the end of the vector. Since the code never modifies what an iterator
points to, so acoording to the convention to use const
whenever possible, we should use the const-iterator.
However, in C++98, there was no simple way to get a const_iterator
from a non-const
container. To work it out, we might concider using the cast like the following code, which conceptually works but probably won’t compile:
|
|
The problem here is that in C++98, const_iterator
s weren’t acceptable for insertions and erasures, so we cast ci
into its non-const version. However, in C++98, there’s no portable conversion from a const_iterator
to an iterator
1, so the last statement probably won’t compile. The conclusion: const_iterator
s were so much trouble in C++98.
Now that we in the new world of C++11, const_iterator
s are both easy to get and easy to use. Even for non-const containers, we get cbegin
and cend
to produce const_iterator
s:
|
|
Maximally Generic Support
Taking into account that some containers and container-like data structures offer begin
and end
as non-member functions, C++11 added the non-member functions begin
and end
to make sure some generic library code using non-member functions is possible.
C++14 rectified the oversight in C++11, adding the support for cbegin
, cend
, rbegin
, rend
, crbegin
, and crend
. Now we could generalize the code above into a findAndInsert
template as follow:
|
|
If we’re using C++11 and want to write maximally generic code, we may build our own implementation for non-member cbegin
:
|
|
Point here is: through its reference-to-const
parameter, container
, we are invoking the non-member begin
function (provided by C++11) on a const
container, and this process yields a const_iterator
. In fact, this template works even if C
is a built-in array type2.