Reputation: 3925
I wrote this program:
// splits a sentence into words
#include <iostream>
#include <string>
#include <algorithm>
#include "spacefunc.h"
using std::string;
using std::cout;
using std::endl;
using std::find_if;
int main() {
typedef string::const_iterator iter;
string input = "This is me";
iter i = input.begin();
while (i != input.end()) {
iter j;
i = find_if(i, input.end(), notspace);
j = find_if(i, input.end(), is_space);
cout << string(i, j) << endl;
i = j;
}
return 0;
}
It fails with following errors:
word_splitter.cpp: In function ‘int main()’:
word_splitter.cpp:21:45: error: no matching function for call to ‘find_if(iter&, std::__cxx11::basic_string<char>::iterator, bool (&)(char))’
i = find_if(i, input.end(), notspace);
^
In file included from /usr/include/c++/5/algorithm:62:0,
from word_splitter.cpp:4:
/usr/include/c++/5/bits/stl_algo.h:3806:5: note: candidate: template<class _IIter, class _Predicate> _IIter std::find_if(_IIter, _IIter, _Predicate)
find_if(_InputIterator __first, _InputIterator __last,
^
/usr/include/c++/5/bits/stl_algo.h:3806:5: note: template argument deduction/substitution failed:
word_splitter.cpp:21:45: note: deduced conflicting types for parameter ‘_IIter’ (‘__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >’ and ‘__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >’)
i = find_if(i, input.end(), notspace);
^
word_splitter.cpp:22:45: error: no matching function for call to ‘find_if(iter&, std::__cxx11::basic_string<char>::iterator, bool (&)(char))’
j = find_if(i, input.end(), is_space);
^
In file included from /usr/include/c++/5/algorithm:62:0,
from word_splitter.cpp:4:
/usr/include/c++/5/bits/stl_algo.h:3806:5: note: candidate: template<class _IIter, class _Predicate> _IIter std::find_if(_IIter, _IIter, _Predicate)
find_if(_InputIterator __first, _InputIterator __last,
^
/usr/include/c++/5/bits/stl_algo.h:3806:5: note: template argument deduction/substitution failed:
word_splitter.cpp:22:45: note: deduced conflicting types for parameter ‘_IIter’ (‘__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >’ and ‘__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >’)
j = find_if(i, input.end(), is_space);
If I change i, j
to iterator
type, it compiles.
What am I doing wrong, as I am pretty sure that find_if
accepts const_iterator
type arguments?
EDIT
If this is the issue of i
being a const_iterator
and input.end() being an iterator
, why does the following code work? This is from Accelerated C++
.
vector < string > split(const string & str) {
typedef string::const_iterator iter;
vector < string > ret;
iter i = str.begin();
while (i != str.end()) {
// ignore leading blanks
i = find_if(i, str.end(), not_space);
// find end of next word
iter j = find_if(i, str.end(), space);
// copy the characters in [i, j)
if (i != str.end())
ret.push_back(string(i, j));
i = j;
}
return ret;
}
Upvotes: 4
Views: 3564
Reputation: 42082
Others have explained why you experienced a compilation error. In my view, future mistakes can be avoided if you express more directly your "ultimate" intention, and let automatic type deduction take care of the rest. For example: if you want your input to be immutable, use const
to mark it as such, and let auto
take care of the rest.
#include <cctype>
#include <iostream>
#include <algorithm>
#include <string>
bool is_space(char c) { return std::isspace(c); }
bool is_not_space(char c) { return not is_space(c); }
int main() {
const std::string input{"This is me"};
for (auto it = input.begin(); it != input.end();) {
it = std::find_if(it, input.end(), is_not_space);
auto it_end = std::find_if(it, input.end(), is_space);
std::cout << std::string(it, it_end) << "\n";
it = it_end;
}
}
Sample run:
$ clang++ example.cpp -std=c++17 -Wall -Wextra
$ ./a.out
This
is
me
Upvotes: 5
Reputation: 25317
find_if
's signature looks like this:
template<class InputIt, class UnaryPredicate> InputIt find_if(InputIt first, InputIt last, UnaryPredicate p);
It expects its first 2 arguments to be of the same type. With find_if(i, input.end(), notspace)
, if i
is a string::const_iterator
, it's not the same type as input.end()
which would be a string::iterator
since input
is non-const. If input
was a const std::string
, input.end()
would return a string::const_iterator
Post C++11, it's uncommon to see a typedef string::const_iterator iter
. Use of auto
is more common:
string input = "This is me";
auto i = input.begin();
Upvotes: 7
Reputation: 76305
find_if
accepts non-const iterators and const_iterators; however, the iterators that you pass to it have to be the same type. The problem here is that input.end()
returns a non-const iterator, because input
is not a const object. That's not the same type as the const iterator 'i'. To get a const end iterator for a non-const object (or for a const object, but that's a distraction), use input.cend()
.
Upvotes: 8