views:

285

answers:

4

Hi,

I found the following code in the book "Accelerated C++" (Chapter 6.1.1), but I can't compile it. The problem is with the find_if lines. I have the necessary includes (vector, string, algorithm, cctype). Any idea?

Thanks, Jabba

bool space(char c) {
    return isspace(c);
}

bool not_space(char c) {
 return !isspace(c);
}

vector<string> split_v3(const string& str)
{
 typedef string::const_iterator iter;
 vector<string> ret;
 iter i, j;

 i = str.begin();
 while (i != str.end())
 {
  // ignore leading blanks
  i = find_if(i, str.end(), not_space);

  // find end of next word
  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;
}
A: 

Off hand, I would say it should probably be

i = str.find_if( ...
j = str.find_if( ...
Charles
Nope, `template<class InputIterator, class Predicate> InputIterator find_if(InputIterator first, InputIterator last, Predicate pred);` is an inline function acting on iterators defined in `<algorithm>` -- not a method on strings or vectors or anything like that.
ephemient
A: 

There is no problem in the code you posted. There is a very obvious problem with the real code you linked to: is_space and space are member functions, and they cannot be called without an instance of Split2. This requirement doesn't make sense, though, so at least you should make those functions static.

(Actually it doesn't make much sense for split_v3 to be a member function either. What does having a class called Split2 achieve over having just a free function - possibly in a namespace?)

UncleBens
To work around this: use a struct as a predicate instead of a function. This way you still get "encapsulation" if you declare it as an nested class.
pmr
You are right, if I put them in a class, those functions must be static. I prefer putting everything in classes (I used Java before). Is it a bad habit?Thanks for the answers, the problem is solved.
Jabba
pmr: could you post an example for that?
Jabba
+1  A: 

As requested:

class SplitV2 {
 public:
  void foo();
 private:
  struct space { bool operator() (char c) { return isspace(c); } };
  struct not_space {
    Split2::space space;
    bool operator() (char c) { return !space(c); }
  };

Use them with std::find_if(it, it2, space()) or std::find_if(it, it2, not_space().
Notice that not_space has a default constructed space as a member variable. It may be not wise to construct space in every call to bool not_space::operator() but maybe the compiler could take care of this. If the syntax for overloading operator() confuses you and you would like to know more about using structs as Predicates you should have a look at operator overloading and some guidelines to the STL.

pmr
Why bother with `space` and `not_space` when you can use `ptr_fun(isspace)` and `not1(ptrfun(isspace))` from `<functional>`?
ephemient
Because as stated `isspace` (from <cctype>) expects an `int` convertible to an `unsigned char` which is error-prone. This way you neatly wrap the difficulty so that it's easy to use.
Matthieu M.
+1  A: 

Writing this in a more STL-like manner,

#include <algorithm>
#include <cctype>
#include <functional>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

using namespace std;

template<class P, class T>
void split(const string &str, P pred, T output) {
    for (string::const_iterator i, j = str.begin(), str_end = str.end();
            (i = find_if(j, str_end, not1(pred))) != str_end;)
        *output++ = string(i, j = find_if(i, str_end, pred));
}

int main() {
    string input;
    while (cin >> input) {
        vector<string> words;
        split(input, ptr_fun(::isspace), inserter(words, words.begin()));
        copy(words.begin(), words.end(), ostream_iterator<string>(cout, "\n"));
    }
    return 0;
}
ephemient
minor point, but `using namespace std;` should be avoided imho.
Matthieu M.
I normally avoid `using namespace` too, but for this short example I preferred to avoid over-80 column lines.
ephemient