Most predicates are cheap to copy, so this isn't usually an issue.
If you have one that really is expensive to copy, you can (often) use std::reference_wrapper
to provide a wrapper that's cheap to copy. Here's a quick demo:
#include <iostream>
#include <thread>
#include <algorithm>
#include <vector>
#include <chrono>
using namespace std::literals;
struct Predicate {
Predicate() = default;
Predicate(Predicate const &) { std::this_thread::sleep_for(1s); }
bool operator()(int i) const { return i == 10; }
};
int main() {
Predicate p;
using namespace std::chrono;
std::vector<int> foo { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto start = high_resolution_clock::now();
auto pos1 = std::find_if(foo.begin(), foo.end(), p);
auto mid = high_resolution_clock::now();
auto pos = std::find_if(foo.begin(), foo.end(), std::ref(p));
auto end = high_resolution_clock::now();
std::cout << pos - foo.begin() << '\n';
std::cout << pos1 - foo.begin() << '\n';
std::cout << "bare: " << duration_cast<seconds>(mid-start).count() << " s\n";
std::cout << "wrap: " << duration_cast<nanoseconds>(end-mid).count() << " ns\n";
}
When I run this, I get output like this:
9
9
bare: 5 s
wrap: 168 ns
So, it looks like 5 copies are being made. When using the "bare" Predicate
object, the search takes 5 seconds. When using the wrapped one, it takes 168 nanoseconds (including the search, not just copying the Predicate
).
I believe that should work with operator()
either const
qualified or not. I haven't checked on the rvalue reference qualified version, but I'm pretty sure that would take more work (reference_wrapper
explicitly deletes ref(&&)
, and that's probably for good reason, so supporting rvalue references may be non-trivial, but I've never dealt with that specific situation so I haven't tried to think though why it's a problem).