如何复制“算法”标头类型函数?

Ast*_*tar 1 c++ c++20

就像 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::iteratorchk 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)

Ala*_*les 5

通过使用,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)

编译器无法知道ABCDE应该都是同一类型。如果您更改chk为:

template< typename Iterator >
Iterator chk(Iterator start, Iterator end, std::function<bool (Iterator, int)>& find, int what)
Run Code Online (Sandbox Code Playgroud)

我们已经接近了,但仍然有两个问题:

  1. 您正在使用find非常量引用,因此类型必须完全匹配
  2. 编译器仍然无法推断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检查,因为它是不必要的。