如何复制`algorithm`头文件中的类型函数?

huangapple go评论60阅读模式
英文:

How can I replicate `algorithm` header type functions?

问题

以下是您提供的代码的翻译部分:

#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;     //是否真的有必要?
    }
};

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)};
    
    //测试
    std::cout << "旧数组\n";
    
    for (int x: series)
        std::cout << x << ' ';
        
    std::cout << "\n新数组\n";
    
    *l = 666;
    
    for (int x: series)
        std::cout << x << ' ';
}

请注意,由于这是一个翻译请求,我只提供了您的代码的翻译部分,没有额外的回答或解释。如果您需要任何额外的解释或帮助,请随时提出具体的问题。

英文:

Just like algorithms in algo header like
std::sort(std::begin(), std::end(), greater)
where greater is a bool func

I am trying to do the same for understanding as how it works actually.
So I am trying to do the same by
1 -> making a lambda func in a separate namespace
2 -> making a separate function like std::sort in other namespace
3 -> passing a vector and it supposed to return a pointer to the element to find

And i am getting error:

&lt;source&gt;: In function &#39;int main()&#39;:
&lt;source&gt;:41:22: error: no matching function for call to &#39;chk(std::vector&lt;int&gt;::iterator, std::vector&lt;int&gt;::iterator, lambda::&lt;lambda(auto:16, int)&gt;&amp;, int)&#39;
   41 |     auto l {test::chk(series.begin(), series.end(), lambda::find, 50)};
      |             ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
&lt;source&gt;:22:10: note: candidate: &#39;template&lt;class auto:17, class auto:18, class auto:19&gt; auto test::chk(auto:17, auto:18, std::function&lt;bool(auto:19, int)&gt;&amp;, int)&#39;
   22 |     auto chk(auto start, auto end, std::function&lt;bool (auto, int)&gt;&amp; find, int what)
      |          ^~~
&lt;source&gt;:22:10: note:   template argument deduction/substitution failed:
&lt;source&gt;:41:22: note:   &#39;lambda::&lt;lambda(auto:16, int)&gt;&#39; is not derived from &#39;std::function&lt;bool(auto:19, int)&gt;&#39;
   41 |     auto l {test::chk(series.begin(), series.end(), lambda::find, 50)};
      |             ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

As per the error I tried putting std::iterator at chk func call at line no 41 but it gives even more error

help me with this

code:

#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;    //
#include &lt;functional&gt;    //std::function
#include &lt;iterator&gt;     //std::iterator

using vec = std::vector&lt;int&gt;;

namespace lambda
{
    auto find{
        [](auto start, int what) -&gt; bool
        {
            if(*start == what)
                return true;
        }
    };
};

namespace test
{
    auto chk(auto start, auto end, std::function&lt;bool (auto, int)&gt;&amp; 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 &lt;&lt; &quot;Old array\n&quot;;
    
    for(int x: series)
        std::cout &lt;&lt; x &lt;&lt; &#39; &#39;;
        
    std::cout &lt;&lt; &quot;\nNew array\n&quot;;
    
    *l = 666;
    
    for(int x: series)
        std::cout &lt;&lt; x &lt;&lt; &#39; &#39;;
}

答案1

得分: 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);

编译器无法知道 ABCDE 应该是相同的类型。
如果将 chk 更改为:

template <typename Iterator>
Iterator chk(Iterator start, Iterator end, std::function<bool(Iterator, int)>& find, int what)

我们更接近了,但仍然存在两个问题:

  1. 您以非 const 引用方式获取 find,因此类型必须完全匹配。
  2. 编译器仍然无法推断出 std::function 所需的类型,因为它阻止了这种类型推断。

如果我们更改为标准算法的更常规形式,只将谓词作为模板:

template <typename Iterator, typename Predicate>
Iterator chk(Iterator start, Iterator end, Predicate find, int what)

然后您的代码将会编译。这样做的额外好处是不涉及 std::function 的开销,而且会直接使用(并且可能会内联)lambda。

您可以使用 concept 来限制 Predicate 类型以匹配您的要求,以改进如果使用不正确的谓词而导致的编译器错误。

find 仅返回 true,您需要在所有情况下返回,否则您的代码将具有未定义的行为:

auto find{
  [](auto start, int what) -> bool
  {
      if(*start == what)
          return true;
      else
          return false;
  }

或者更简单一些:

auto find{
  [](auto start, int what) -> bool
  {
      return *start == what;
  }

最后,您的谓词对于标准算法来说是不寻常的,因为它接受一个迭代器而不是一个值,将其更改为一个值会导致:

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;
    }
};

请注意,我还删除了 start == end 检查,因为这是不必要的。

英文:

By using auto you end up with each parameter having a different type and the compiler has no way to deduce what all of the parameters should be (see the template argument deduction/substitution failed part of the error message).

Replacing the auto with normal templates gives:

template &lt;typename A&gt;
bool find =
[](A start, int what) ...
template &lt;typename B, typename C, typename D, typename E&gt;
E chk(A start, B end, std::function&lt;bool (C, int)&gt;&amp; find, int what);

The compiler has no way to know that A, B, C, D and E should all be the same type.
If you change chk to:

template&lt; typename Iterator &gt;
Iterator chk(Iterator start, Iterator end, std::function&lt;bool (Iterator, int)&gt;&amp; find, int what)

We're closer but still have two issues:

  1. You're taking find by a non-const reference so the types have to match exactly
  2. The compiler still can't deduce the type required for the find lambda as std::function prevents this kind of type deduction.

If we change to the more conventional form of the std algorithms of just taking the predicate as a template:

template&lt; typename Iterator, typename Predicate &gt;
Iterator chk(Iterator start, Iterator end, Predicate find, int what)

Then your code compiles. This has the added benefit of not involving the overhead of std::function and will use (and probably inline) the lambda directly.

You can use a concept to restrict the type of Predicate to match your requirements to improve compiler errors if used with an incorrect predicate.

find only ever returns true, you need to return in all cases otherwise your code has undefined behaviour:

auto find{
[](auto start, int what) -&gt; bool
{
if(*start == what)
return true;
else
return false;
}

Or more simply:

auto find{
[](auto start, int what) -&gt; bool
{
return *start == what;
}

Finally your predicate is unusual for a std algorithm in that it takes an iterator rather than a value, changing it to a value results in:

namespace lambda
{
auto find{
[](int value, int what)
{
return value == what;
}
};
};
namespace test
{
template&lt; typename Iterator, typename Predicate &gt;
Iterator chk(Iterator start, Iterator end, Predicate find, int what)
{
for(;start != end; ++start)
{
if(find(*start, what))
return start;
}
return end;
}
};

Note I've also removed the start == end check as it's unnecessary.

huangapple
  • 本文由 发表于 2023年4月17日 13:56:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76032067.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定