以下是
std::find_if
的定义
template< class InputIt, class UnaryPredicate >
constexpr InputIt find_if( InputIt first, InputIt last, UnaryPredicate p );
为什么不使用
UnaryPredicate&& p
作为参数?
如果我的谓词很难复制,我该怎么办?
以下情况是否应该区别对待?
UnaryPredicate::operator()
是 const 合格的(通常应该是这样)UnaryPredicate::operator()
不是 const 合格的。UnaryPredicate::operator() &&
(看到这很疯狂吗?)我将传递一个右值作为预测变量。大多数谓词的复制成本很低,所以这通常不是问题。
如果你有一个复制起来真的很昂贵,你可以(经常)使用
std::reference_wrapper
来提供一个复制起来很便宜的包装器。这是一个快速演示:
#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";
}
当我运行它时,我得到这样的输出:
9
9
bare: 5 s
wrap: 168 ns
因此,看起来正在制作 5 个副本。使用“裸”
Predicate
对象时,搜索需要 5 秒。使用wrapped的时候,需要168纳秒(包括搜索,不只是复制Predicate
)。
我相信应该与
operator()
一起工作,无论const
合格与否。我还没有检查右值引用合格版本,但我很确定这需要更多工作(reference_wrapper
明确删除 ref(&&)
,这可能是有充分理由的,所以支持右值引用可能很重要) .