Wednesday, January 20, 2010

Tricky error during std::find function applied on std::string

An tricky problem is described here that is worth mentioning. Look at this code chunk:


int count(std::string& s, char c) {
std::string::const_iterator i = std::find(s.begin(), s.end(), c);
int n = 0;
while (i != s.end()) {
n++;
i = std::find(i+1, s.end(), c);
}
return n;
}


If you try to compile this function (offcourse adding main function with required headers), you will find that the first call to find doesn't produce any error. But the second call within the loop generates compilation error of this form:


In function ‘int count(std::string&, char)’:
error: no matching function for call to ‘find(__gnu_cxx::__normal_iterator, std::allocator > >, __gnu_cxx::__normal_iterator, std::allocator > >, char&)’


At first look, it seems to be weird. But it's not :)

The general find function is declared as:


template
InputIterator find(
InputIterator _First,
InputIterator _Last,
const Type& _Val
);


You can see that the type of the first and second parameters of the function template correspond to the same type. The compiler cannot deduce that it is this function that you want to call if your call has a combination of string::const_iterator and string::iterator as arguments.

During first call, i.e. std::find(s.begin(), s.end(), c), the first and second arguments are of string::iterator types and the return value is also of type string::iterator. But this return value is being casted to string::const_iterator.

During second call, i.e. std::find(i+1, s.end(), c), the first argument is of type string::const_iterator (due to that earlier casting) and the second argument is of type string::iterator. So, the types of first and second arguments don't match. That's why , the compiler is generating the error.

Here goes two different types of fixes.

Fix 1:


int count(std::string& s, char c) {
std::string::iterator i = std::find(s.begin(), s.end(), c);
int n = 0;
while (i != s.end()) {
n++;
i = std::find(i+1, s.end(), c);
}
return n;
}


Fix 2:


int count(const std::string& s, char c) {
std::string::const_iterator i = std::find(s.begin(), s.end(), c);
int n = 0;
while (i != s.end()) {
n++;
i = std::find(i+1, s.end(), c);
}
return n;
}


Tricky error..isn't it? ;)

No comments: