在容器中查找元素的标准化方法?

Standardized way to find an element in a container?

是否有在容器中搜索值((unordered_)map 的键)的标准化方法?

通过这个函数的例子:

template <class T, class V> bool find(T const &t, V const &v) {
    // For std::vector : return std::find(t.begin(), t.end(), v) != t.end();
    // For std::(unordered_)set and (unordered_)map : return t.find(v) != t.end();
    return ?
}

我使用:

template <class T, class V> bool find(T const &t, V const &v) {
    return std::find(t.begin(), t.end(), v) != t.end();
}

template <class V> bool find(std::set<V> const &t, V const &v) {
    return t.find(v) != t.end();
}

template <class V> bool find(std::unordered_set<V> const &t, V const &v) {
    return t.find(v) != t.end();
}

template <class K, class V> bool find(std::map<K, V> const &t, K const &v) {
    return t.find(v) != t.end();
}

template <class K, class V> bool find(std::unordered_map<K, V> const &t, K const &v) {
    return t.find(v) != t.end();
}

但是std有这种东西吗?

所以您基本上是在问是否有一个函数可以为您调用 t.find?不。库基础 TS v2 提出了一系列非成员 eraseerase_if 重载,它们是这样实现的:

  template<typename _Key, typename _Compare, typename _Alloc,
       typename _Predicate>
    inline void
    erase_if(set<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
    { __detail::__erase_nodes_if(__cont, __pred); }

  template<typename _Key, typename _Compare, typename _Alloc,
       typename _Predicate>
    inline void
    erase_if(multiset<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
    { __detail::__erase_nodes_if(__cont, __pred); }

另一方面,这里是 list 的重载:

  template<typename _Tp, typename _Alloc, typename _Predicate>
    inline void
    erase_if(list<_Tp, _Alloc>& __cont, _Predicate __pred)
    { __cont.remove_if(__pred); }

  template<typename _Tp, typename _Alloc, typename _Up>
    inline void
    erase(list<_Tp, _Alloc>& __cont, const _Up& __value)
    {
      using __elem_type = typename list<_Tp, _Alloc>::value_type;
      erase_if(__cont, [&](__elem_type& __elem) { return __elem == __value; });
    }

如您所见,无法统一擦除。逻辑类似地扩展到 find。你的方法很好,但我会遵循标准的风格,并为比较器、分配器等添加模板参数,以保持健壮性。

您可以为 find_if 函数提供一元谓词

template <class K, class V> bool find(std::unordered_map<K, V> const &t, K  const &v) {
    return std::find_if(t.begin(), t.end(), [v](const std::pair<K, V>& x) {return x.first == v; }) != t.end();
}

int main()
{  
    std::unordered_map<int,char> example = {{1,'a'},{2,'b'}};
    std::cout << find(example, 2);  // true
    std::cout << find(example, 3);  // false
}

没有任何标准可以为您执行此操作 - 但我们可以轻松编写这样的解决方案。 "special" 部分是容器是否具有 find() 成员函数。如果是这样,我们应该使用它。如果没有,我们将退回到使用 std::find()。无论如何,我们想将结果与 end() 进行比较。

所以我们为 .find() 写了一个 preferred 重载,为另一个写了一个 fallback 重载:

template <class C, class V>
auto generic_find_impl(C const& container, V const& value, int /* unused */)
    -> decltype(container.find(value))
{
    return container.find(value);
}

template <class C, class V>
auto generic_find_impl(C const& container, V const& value, ...)
{
    using std::begin;
    using std::end;
    return std::find(begin(container), end(container), value);
}

template <class C, class V>
bool generic_find(C const& container, V const& value) {
    using std::end;
    return generic_find_impl(container, value, 0) != end(container);
}

如果 container.find(value) 是有效表达式,由于最后一个参数,第一个重载将是首选(int... 更适合 0) .如果它不是一个有效的表达式,那么第一个重载是不可行的,我们只会得到第二个重载。