Professional C__ - Marc Gregoire [230]
// Code for inputting scores into the vector omitted, similar as earlier.
auto end = myVector.end();
auto it = find_if(myVector.begin(), end,
not1(bind2nd(greater_equal if (it == end) { cout << "All perfect scores" << endl; } else { cout << "Found a \"less-than-perfect\" score of " << *it << endl; } Code snippet from FunctionObjects\Negators.cpp The function not1() complements the result of every call to the predicate it takes as an argument. Of course, you could also just use less instead of greater_equal. There are cases, often when using nonstandard functors, that not1() comes in handy. The “1” in not1() refers to the fact that its operand must be a unary function (one that takes a single argument). If its operand is a binary function (takes two arguments), you must use not2() instead. Note that you use not1() in this case because, even though greater_equal is a binary function, bind2nd() has already converted it to a unary function, by binding the second argument always to 100. As you can see, using functors and adapters can quickly become complicated. Our advice is to use C++11 lambda expressions and use functors sparingly. For example, the previous find_if() call using the not1() negator can be written more elegantly using a lambda expression: auto it = find_if(myVector.begin(), end, [](int i){ return i < 100; }); Code snippet from FunctionObjects\Negators.cpp Calling Member Functions If you have a container of objects, you sometimes want to pass a pointer to a class method as the callback to an algorithm. For example, you might want to find the first empty string in a vector of strings by calling empty() on each string in the sequence. However, if you just pass a pointer to string::empty() to find_if(), the algorithm has no way to know that it received a pointer to a method instead of a normal function pointer or functor. The code to call a method pointer is different from that to call a normal function pointer, because the former must be called in the context of an object. C++11 provides a conversion function called mem_fn() that you can call on a method pointer before passing it to an algorithm. The following example demonstrates this. Note that you have to specify the method pointer as &string::empty. The &string:: part is not optional. See Chapter 21 for details. void findEmptyString(const vector { auto end = strings.end(); auto it = find_if(strings.begin(), end, mem_fn(&string::empty)); if (it == end) { cout << "No empty strings!" << endl; } else { cout << "Empty string at position: " << it - strings.begin() << endl; } } Code snippet from FunctionObjects\EmptyString.cpp mem_fn() generates a function object that serves as the callback for find_if(). Each time it is called back, it calls the empty() method on its argument. mem_fn() works exactly the same when you have a container of pointers to objects instead of objects themselves. For example: void findEmptyString(const vector { auto end = strings.end(); auto it = find_if(strings.begin(), end, mem_fn(&string::empty)); // Remaining of function omitted because it is the same as earlier } Code snippet from FunctionObjects\EmptyStringPtr.cpp If your compiler does not yet support the C++11 mem_fn(), you have to use mem_fun_ref() when you have a container of objects as follows: auto it = find_if(strings.begin(), end, mem_fun_ref(&string::empty)); Code snippet from FunctionObjects\EmptyString.cpp However, if you have a container of pointers to objects and you can’t use the C++11 mem_fn(), then you have to use mem_fun() as follows: auto it = find_if(strings.begin(), end, mem_fun(&string::empty)); Code snippet from FunctionObjects\EmptyStringPtr.cpp mem_fun_ref() and mem_fun() work in restricted cases. If the method takes 0 arguments, the result can be used as a callback for a unary function;