为啥像这样使用 find_if 会失败?

Posted

技术标签:

【中文标题】为啥像这样使用 find_if 会失败?【英文标题】:Why using find_if like this fail?为什么像这样使用 find_if 会失败? 【发布时间】:2016-10-20 15:24:18 【问题描述】:

我想从地图中找到第一个非零元素,因此我执行了以下代码:

#include <map>
#include <iostream>
#include <algorithm>

bool nonzero(std::map<char,int>::const_iterator& it);

int main()  
    std::map<char, int> m;
    m['a'] = 0;
    m['b'] = 1;
    std::map<char,int>::iterator it = std::find_if(m.begin(), m.end(), nonzero);
    std::cout << it->first << '\t' << it->second << std::endl;
    return 0;



bool nonzero(std::map<char,int>::const_iterator& it)    
    return it->second;

g++给出的错误很复杂,说是:

/usr/include/c++/5/bits/predefined_ops.h:234:30: error: invalid initialization of reference of type ‘std::_Rb_tree_const_iterator<std::pair<const char, int> >&’ from expression of type ‘std::pair<const char, int>’
   return bool(_M_pred(*__it)); 

我不明白它在说什么以及为什么我的程序会失败。

【问题讨论】:

find_if*i 传递给您的函数,而不是 i 仔细检查谓词要求here 查找任何个使用std::find_if的例子。 【参考方案1】:

find_if 调用的 nonzero 函数的预期类型不是std::map&lt;char,int&gt;::const_iterator&amp;,而是const std::pair&lt;const char, int&gt; &amp;

事实上,如果你检查一些online documentation for find_if,你会看到一元谓词的形式是:

bool UnaryPredicate(const Type&)

其中Type 在您的情况下为std::pair&lt;const char, int&gt;(对于一般的std::map&lt;Key, Value&gt;,类型为std::pair&lt;const Key, Value&gt;)。

因此,您可以调整将const&amp; 传递给std::pair 的函数:

bool nonzero(const std::pair<const char, int> & p)

    return (p.second != 0);

请注意,将 C++14 auto 与 lambda 一起使用会简化您的代码,例如:

auto it = std::find_if(m.begin(), m.end(), [](const auto& p)
    return (p.second != 0);
);

另请注意,该对的一般形式为std::pair&lt;const Key, Value&gt;(不仅仅是pair&lt;Key, Value&gt; 和非常量键)。

【讨论】:

【参考方案2】:

find_ifvalue_type(实际上是iterator.operator*())传递给传递给它的函数/函数对象。您的 nonzero 应该接受 std::map&lt;char,int&gt;::value_type const&amp; 作为参数,或者更简洁地说:std::pair&lt;const char, int&gt; const&amp;

bool nonzero(std::pair<const char, int> const& element) 
    return it.second;

请注意,该对的密钥是const。如果您省略它,您将复制您检查的每个地图元素。

如果您可以使用 C++14 或更高版本,您还可以使用 auto 和通用 lambda 使其更短:

auto it = std::find_if(m.begin(), m.end(), [](auto const& pair) return p.second; );

和C++11版本:

auto it = std::find_if(m.begin(), m.end(), [](std::pair<const char, int> const& pair) return p.second; )

【讨论】:

注意,lambda 仅适用于 C++11 或更高版本。【参考方案3】:

函数接受:

bool nonzero(const std::map<char,int>::value_type& value);

这是std::pair&lt;const char,int&gt;,不是迭代器

在使用该迭代器之前,您应该通过与std::map::end() 比较来检查find_if 的结果。

【讨论】:

以上是关于为啥像这样使用 find_if 会失败?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 std::find_if(first, last, p) 不采用引用谓词?

在 find_if 中使用谓词

c++编译错误“需要'_InputIterator std::__find_if(_InputIterator, _InputIterator, _Predicate, std::input_iter

使用std::find_if提取序列容器的子串

具有多个谓词的 C++11 算法

STL_算法_查找算法(findfind_if)