问题描述
我正在学习 C++,我正在尝试实现一个二分查找函数,该函数查找谓词所包含的第一个元素.该函数的第一个参数是一个向量,第二个参数是一个计算给定元素谓词的函数.二分查找函数如下所示:
I'm learning C++, and I'm trying to implement a binary search function that finds the first element for which a predicate holds. The function's first argument is a vector and the second argument is a function that evaluates the predicate for a given element. The binary search function looks like this:
template <typename T> int binsearch(const std::vector<T> &ts, bool (*predicate)(T)) {
...
}
如果这样使用,它会按预期工作:
This works as expected if used like this:
bool gte(int x) {
return x >= 5;
}
int main(int argc, char** argv) {
std::vector<int> a = {1, 2, 3};
binsearch(a, gte);
return 0;
}
但是如果我使用 lambda 函数作为谓词,我会得到一个编译器错误:
But if I use a lambda function as a predicate, I get a compiler error:
search-for-a-range.cpp:20:5: error: no matching function for call to 'binsearch'
binsearch(a, [](int e) -> bool { return e >= 5; });
^~~~~~~~~
search-for-a-range.cpp:6:27: note: candidate template ignored: could not match 'bool (*)(T)' against '(lambda at
search-for-a-range.cpp:20:18)'
template <typename T> int binsearch(const std::vector<T> &ts,
^
1 error generated.
以上错误是由
binsearch(a, [](int e) -> bool { return e >= 5; });
怎么了?为什么编译器不相信我的 lambda 有正确的类型?
What's wrong? Why is the compiler not convinced that my lambda has the right type?
推荐答案
你的函数 binsearch
接受一个函数指针作为参数.lambda 和函数指针是不同的类型:可以将 lambda 视为实现 operator()
的结构体实例.
Your function binsearch
takes a function pointer as argument. A lambda and a function pointer are different types: a lambda may be considered as an instance of a struct implementing operator()
.
请注意,无状态 lambda(不捕获任何变量的 lambda)可隐式转换为函数指针.由于模板替换,这里隐式转换不起作用:
Note that stateless lambdas (lambdas that don't capture any variable) are implicitly convertible to function pointer. Here the implicit conversion doesn't work because of template substitution:
#include <iostream>
template <typename T>
void call_predicate(const T& v, void (*predicate)(T)) {
std::cout << "template" << std::endl;
predicate(v);
}
void call_predicate(const int& v, void (*predicate)(int)) {
std::cout << "overload" << std::endl;
predicate(v);
}
void foo(double v) {
std::cout << v << std::endl;
}
int main() {
// compiles and calls template function
call_predicate(42.0, foo);
// compiles and calls overload with implicit conversion
call_predicate(42, [](int v){std::cout << v << std::endl;});
// doesn't compile because template substitution fails
//call_predicate(42.0, [](double v){std::cout << v << std::endl;});
// compiles and calls template function through explicit instantiation
call_predicate<double>(42.0, [](double v){std::cout << v << std::endl;});
}
你应该让你的函数 binsearch
更通用,比如:
template <typename T, typename Predicate>
T binsearch(const std::vector<T> &ts, Predicate p) {
// usage
for(auto& t : ts)
{
if(p(t)) return t;
}
// default value if p always returned false
return T{};
}
从标准算法库中汲取灵感.
这篇关于将 lambda 传递给函数模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!