auto
is a type placeholder that may be used in variable declarations to instruct the compiler to infer the type from the
initializer.
The use of auto
reduces unnecessary boilerplate in situations where the type of the variable is apparent from the context (see rule
S5827). In other situations, though, whether auto
increases or decreases readability is a matter of personal taste.
In the case of variables initialized from a function that conventionally returns an iterator (e.g., begin
, end
,
std::find
), it is clear that the type of the variable is some iterator. Spelling the exact type of the iterator in such a situation does
not improve the clarity of the code, especially considering the usual verbosity of such types. The same can be said for functions returning
ranges.
This rule raises an issue on the declaration of a variable that is initialized with the return value of a function that conventionally returns an
iterator when the variable is declared with an explicit type equal to the function’s return type. The detected functions are:
-
begin
and end
functions and their const and reverse variants
- standard algorithms that return iterators or ranges
Noncompliant code example
std::vector<int>::iterator someFunction(std::vector<int>& v);
void f() {
std::vector<int> v;
const std::vector<int>& cv = v;
std::vector<int>::iterator it1 = v.begin(); // Noncompliant
std::vector<int>::const_iterator it2 = v.cbegin(); // Noncompliant
std::vector<int>::const_iterator it3 = cv.cbegin(); // Noncompliant
std::vector<int>::const_iterator it4 = std::begin(cv); // Noncompliant
std::vector<int>::iterator it5 = std::find(v.begin(), v.end(), 10); // Noncompliant
std::map<int, std::string> m;
if (std::map<int, std::string>::iterator it = m.find(20); it != m.end()) { // Noncompliant
// do something
}
}
Compliant solution
std::vector<int>::iterator someFunction(std::vector<int>& v);
void f() {
std::vector<int> v;
const std::vector<int>& cv = v;
auto it1 = v.begin();
auto it2 = v.cbegin();
auto it3 = cv.cbegin();
auto it4 = std::begin(cv);
std::vector<int>::const_iterator it5 = v.begin(); // Compliant, the type is different
std::vector<int>::iterator it6 = someFunction(10); // Compliant, the function is not a well-known function returning an iterator
auto it7 = std::find(v.begin(), v.end(), 10);
std::vector<int>::iterator it8 = someFunction(10);
std::map<int, std::string> m;
if (auto it = m.find(20); it != m.end()) {
// do something
}
}