Why is this an issue?
It is often considered a better style to access objects in generic code with free functions than with member functions, because it allows to adapt
an object to a template without modifying it, just by adding the right overload of the free function. This is especially true with containers, which
can come in a wide variety (and some of them can’t even have member function, for instance, C-style arrays).
Therefore, the C++ standard library provides free functions that can be applied on any standard container, and that can be adapted for user-defined
containers. They are:
- Since C++11:
std::begin
, std::end
, std::cbegin
, std::cend
- Since C++14:
std::rbegin
, std::rend
, std::crbegin
, std::crend
- Since C++17:
std::size
, std::empty
, std::data
- Since C++20:
std::ssize
When writing generic code, you should prefer using those functions for objects that depend on the template arguments: it will allow your code to
work with a broader variety of containers.
Noncompliant code example
template<class T>
bool f(T const &t, std::vector<int> const &v) {
if (!t.empty()) { // Noncompliant in C++17
auto val = (t.begin() // Noncompliant in C++11
->size()); // Noncompliant in C++17
return val == v.size(); // Compliant, v does not depend on a template parameter
}
return false;
}
Compliant solution
template<class T>
bool f(T const &t, std::vector<int> const &v) {
if (!std::empty(t)) { // Compliant
auto val = std::size(*std::begin(t)); // Compliant
return val == v.size();
}
return false;
}