就像 algo header 中的算法一样,
std::sort(std::begin(), std::end(), greater)
where greateris abool func
我正在尝试做同样的事情来理解它的实际工作原理。所以我试图通过
1 -> 在单独的命名空间中创建一个 lambda func
2 -> 像std::sort在其他命名空间中那样创建一个单独的函数
3 -> 传递一个向量,它应该返回一个指向要查找的元素的指针
我收到错误:
<source>: In function 'int main()':
<source>:41:22: error: no matching function for call to 'chk(std::vector<int>::iterator, std::vector<int>::iterator, lambda::<lambda(auto:16, int)>&, int)'
41 | auto l {test::chk(series.begin(), series.end(), lambda::find, 50)};
| ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:22:10: note: candidate: 'template<class auto:17, class auto:18, class auto:19> auto test::chk(auto:17, auto:18, std::function<bool(auto:19, int)>&, int)'
22 | auto chk(auto start, auto end, std::function<bool (auto, int)>& find, int what)
| ^~~
<source>:22:10: note: template argument deduction/substitution failed:
<source>:41:22: note: 'lambda::<lambda(auto:16, int)>' is not derived from 'std::function<bool(auto:19, int)>'
41 | auto l {test::chk(series.begin(), series.end(), lambda::find, 50)};
| ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
根据错误,我尝试将调用放在std::iterator第chk funcno 行41,但它给出了更多错误
帮我解决这个问题
代码:
#include <iostream>
#include <vector>
#include <algorithm> //
#include <functional> //std::function
#include <iterator> //std::iterator
using vec = std::vector<int>;
namespace lambda
{
auto find{
[](auto start, int what) -> bool
{
if(*start == what)
return true;
}
};
};
namespace test
{
auto chk(auto start, auto end, std::function<bool (auto, int)>& find, int what)
{
if(start == end)
return end;
for(;start != end; ++start)
{
if(find(start, what))
return start;
}
return end; //is this really necessary?
}
};
int main()
{
vec series{1, 2, 3, 4, 5, 6, 7, 50, 8, 9, 10, 11, 12};
auto l {test::chk(series.begin(), series.end(), lambda::find, 50)};
//test
std::cout << "Old array\n";
for(int x: series)
std::cout << x << ' ';
std::cout << "\nNew array\n";
*l = 666;
for(int x: series)
std::cout << x << ' ';
}
Run Code Online (Sandbox Code Playgroud)
通过使用,auto您最终会得到每个参数具有不同类型的结果,并且编译器无法推断出所有参数应该是什么(请参阅template argument deduction/substitution failed错误消息的部分)。
用普通模板替换auto可以得到:
template <typename A>
bool find =
[](A start, int what) ...
template <typename B, typename C, typename D, typename E>
E chk(A start, B end, std::function<bool (C, int)>& find, int what);
Run Code Online (Sandbox Code Playgroud)
编译器无法知道A、B、C、D和E应该都是同一类型。如果您更改chk为:
template< typename Iterator >
Iterator chk(Iterator start, Iterator end, std::function<bool (Iterator, int)>& find, int what)
Run Code Online (Sandbox Code Playgroud)
我们已经接近了,但仍然有两个问题:
find非常量引用,因此类型必须完全匹配findlambda 所需的类型,因为std::function它阻止了这种类型推断。如果我们更改为 std 算法的更传统形式,仅将谓词作为模板:
template< typename Iterator, typename Predicate >
Iterator chk(Iterator start, Iterator end, Predicate find, int what)
Run Code Online (Sandbox Code Playgroud)
然后你的代码就会编译。这样做的额外好处是不涉及 lambda 的开销std::function,并且将直接使用(可能是内联)lambda。
如果与不正确的谓词一起使用,您可以使用概念来限制 的类型以满足您的要求,以改善编译器错误。Predicate
find只返回 true,您需要在所有情况下返回,否则您的代码具有未定义的行为:
auto find{
[](auto start, int what) -> bool
{
if(*start == what)
return true;
else
return false;
}
Run Code Online (Sandbox Code Playgroud)
或者更简单地说:
auto find{
[](auto start, int what) -> bool
{
return *start == what;
}
Run Code Online (Sandbox Code Playgroud)
最后,您的谓词对于 std 算法来说是不寻常的,因为它采用迭代器而不是值,将其更改为值会导致:
namespace lambda
{
auto find{
[](int value, int what)
{
return value == what;
}
};
};
namespace test
{
template< typename Iterator, typename Predicate >
Iterator chk(Iterator start, Iterator end, Predicate find, int what)
{
for(;start != end; ++start)
{
if(find(*start, what))
return start;
}
return end;
}
};
Run Code Online (Sandbox Code Playgroud)
请注意,我还删除了该start == end检查,因为它是不必要的。