find_if不使用const_iterator

时间:2018-03-15 16:31:47

标签: c++

我写了这个程序:

// 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;  
}

失败并出现以下错误:

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);

如果我将i, j更改为iterator类型,则会进行编译。

我做错了什么,因为我很确定find_if接受const_iterator类型参数?

修改 如果这是iconst_iterator而input.end()为iterator的问题,为什么以下代码有效?这来自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;
}

3 个答案:

答案 0 :(得分:8)

find_if接受非const迭代器和const_iterators;但是,传递给它的迭代器必须是相同的类型。这里的问题是input.end()返回非const迭代器,因为input不是const对象。这与const迭代器'i'的类型不同。要获得非const对象的const结束迭代器(或对于const对象,但这会分散注意力),请使用input.cend()

答案 1 :(得分:7)

find_if的签名如下所示:

template<class InputIt, class UnaryPredicate>
InputIt find_if(InputIt first, InputIt last, UnaryPredicate p);

它希望它的前两个参数属于同一类型。使用find_if(i, input.end(), notspace)时,如果istring::const_iterator,则与input.end()的类型不同string::iterator,因为input input是非常量的。如果const std::stringinput.end()string::const_iterator将返回typedef string::const_iterator iter

发布C ++ 11后,看到auto的情况并不常见。使用string input = "This is me"; auto i = input.begin(); 更为常见:

{{1}}

答案 2 :(得分:4)

其他人解释了为什么遇到编译错误。在我看来,如果你更直接地表达你的“终极”意图,可以避免未来的错误,让自动类型演绎处理其余的事情。例如:如果您希望输入是不可变的,请使用const将其标记为,并让auto处理其余内容。

#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;
  }
}

示例运行:

$ clang++ example.cpp -std=c++17 -Wall -Wextra
$ ./a.out 
This
is
me