在容器中查找元素的标准化方法?
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 提出了一系列非成员 erase
和 erase_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
) .如果它不是一个有效的表达式,那么第一个重载是不可行的,我们只会得到第二个重载。
是否有在容器中搜索值((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 提出了一系列非成员 erase
和 erase_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
) .如果它不是一个有效的表达式,那么第一个重载是不可行的,我们只会得到第二个重载。