Question:
I'll immediately apologize for such a vague name, I don't know how to describe the task in a nutshell.
Let's say we have a class that does some work:
class Worker{
public:
bool doWork(int arg);
};
The doWork
method returns true
if the job was completed successfully. It is necessary that one of the existing workers do the work. For this I want to use std::find_if
struct DoWork{
int arg;
explicit DoWork(int arg):
arg(arg)
{}
bool operator()(Worker &worker) const{
return worker.doWork(arg);
}
};
std::vector<Worker> workers;
//...
std::find_if(workers.begin(), workers.end(), DoWork(42));
The idea is this. The algorithm will iterate through the workers until one does the job or they run out. But I am tormented by vague doubts that it is possible to do so. Is there undefined behavior here? Will this code always work the same on different stl implementations?
Answer:
The following is clearly defined for the unary function predicate std::find, std::find_if, std::find_if_not:
1) The function must return true for the required element
2) The function prototype should be similar to the entry:
bool pred(const Type &a);
const may be omitted, but the function must never change the data available through the passed object.
3) Type must be such that the iterator can be dereferenced and implicitly converted to Type.
Why is that? The compiler conforming to C++11 allows parallelization and optimizations organized by the compiler itself. What happens if the predicate can change the value of the value? This may cause another pass of the predicate to give a different, i.e. ambiguous, result. A collection can be such that changing another member should lead to a change in order, which is impossible when passing the value of an object by reference, that is, in theory, iterators should change – is the element the first one encountered after the change (and is it in the correct place) turns out to be unknown.
find_if should be similar in behavior to the following implementation.
template<class InputIterator, class UnaryPredicate>
InputIterator find_if (InputIterator first, InputIterator last, UnaryPredicate pred)
{
while (first!=last) {
if (pred(*first)) return first;
++first;
}
return last;
}
Not to be confused: this is by no means a mandatory implementation. The function can be processed in a special way through the compiler's static analyzer, turning it into the most suitable code for a particular case. The predicate argument is passed through an iterator dereference, which assumes that the constant version of the dereference is used.