繁体   English   中英

C ++ STL:std :: find with std :: map

[英]C++ STL: std::find with std::map

Python允许你if e in arr: ...if e in arr: ... if key in dict: ...这很方便。

我们可以使用std::find()std::map来做类似的事情吗? 这将允许我使用单个泛型函数统一处理std::arraystd::map ,而无需显式切换到std::map::find()

但如果重载operator==()是唯一的方法,我宁愿放弃这个想法......

更新:注意我已经有了一种解决方案

通过“重载operator==() ”我的意思是这样的:

template<typename K>
struct KF {
    K&& k;

    template <typename V>
    friend bool operator==(const typename std::pair<const K, V>& pair, const KF<K>& o) {
        return pair.first == o.k;
    }

};

template <typename K>
KF<K> keyFinder(K&& k) { return KF<K>{ std::forward<K>(k) }; }

int main() {
    std::set<int> s{ 1, 2, };
    cout << (std::find(s.begin(), s.end(), 1) == s.end()) << endl; // => 0
    cout << (std::find(s.begin(), s.end(), 3) == s.end()) << endl; // => 1

    std::map<int, int> m{ {1,10}, {2,20}, };
    cout << (std::find(m.begin(), m.end(), keyFinder(1)) == m.end()) << endl; // => 0
    cout << (std::find(m.begin(), m.end(), keyFinder(3)) == m.end()) << endl; // => 1
}

当我们以通用的方式处理非标量K时,事情变得更加复杂(完美的转发等等 ?)

...为什么不编写自己的实用功能?

template <typename TContainer, typename TValue>
bool contains(const TContainer& c, const TValue& x);

您可以使用重载来匹配容器:

template <typename TValue, std::size_t N>
bool contains(const std::array<TValue, N>& c, const TValue& x)
{
    return std::find(std::begin(c), std::end(c), x) != std::end(c);
}

template <typename TValue, typename... Ts>
bool contains(const std::map<Ts...>& c, const TValue& x)
{
    return c.find(x) != std::end(c);
}

用法:

std::array<int, 2> a{1,2};
std::map<int, int> b{{1,2},{3,4}};

assert(contains(a, 1));
assert(!contains(a, 42));
assert(contains(b, 1));
assert(!contains(b, 42));

wandbox上的实例


如果您希望将来支持其他容器,最好使用SFINAE来检查特定表达式是否有效。 这种方法效果很好,因为它不关心容器的类型,它只关心可以对它执行什么操作。

检测习惯用法可能很容易通过SFINAE检查成员的可用性(并且它的实现与C ++ 11兼容)

我还写了一篇关于用C ++ 17原位检查表达式有效性的文章,这可能是一个有趣的读物。 尽管它的标题,它涵盖了C ++ 11,C ++ 14和C ++ 17技术来检查表达式的有效性:

“使用C ++ 17检查表达式有效性”

回答你明确的问题 - 不, std::find将无法统一为std::map / std::unordered_mapstd::array / std::vector因为前者是键/值的集合对和后者是价值的集合......

您可能希望使用std::find_if因为它为您提供了更多的灵活性来定义相等条件,例如像这样(c ++ 1z方法):

#include <array>
#include <map>
#include <string>
#include <algorithm>
#include <type_traits>

template <class T>
struct is_pair: std::false_type { };

template <class K, class V>
struct is_pair<std::pair<K,V>>: std::true_type { };

int main() {
    std::map<std::string, int> m {{"abc", 1}, {"cde", 2}, {"efg", 3}};
    std::array<int, 5> a{1, 2, 3, 4, 5};

    auto lambda = [](auto it) {
        if constexpr (is_pair<decltype(it)>::value) {
            return it.second == 3;
        } else {
            return it == 3;
        }
    };

    assert(std::find_if(a.begin(), a.end(), lambda) != a.end());
    assert(std::find_if(m.begin(), m.end(), lambda) != m.end());
}

[现场演示]

请记住,如果您决定搜索std::vector<std::pair<int, int>>类的集合,则此方法将无法按预期工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM