简体   繁体   中英

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

Python allows you to write if e in arr: ... and if key in dict: ... which is handy.

Can we do something similar with the latter using std::find() and std::map ? That will allow me to uniformly handle std::array and std::map with a single generic function, without explicitly switching to std::map::find() .

But if overloading operator==() is the only way, I'd rather give up this idea...

Update: note I already have a sort of solution

By "overloading operator==() " I meant something like this:

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
}

Things get more complicated when we deal with non-scalar K in an universal way (perfect forwarding etc. ?)

...why not write your own utility function?

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

You can use overloading to match the containers:

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

Usage:

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

live example on wandbox


If you want to support additional containers in the future, it's a good idea to use SFINAE to check whether or not a particular expression is valid. This approach works well because it doesn't care about the type of the container, it only cares about what operations can be performed on it.

The detection idiom would likely make it very easy to check member availability through SFINAE (and its implementation is C++11 compatible) .

I also wrote an article about checking expression validity in-situ with C++17, which could be an interesting read. Despite its title, it covers C++11, C++14 and C++17 techniques to check expression validity:

"checking expression validity in-place with C++17"

To answer your explicit question - no, std::find won't be able to work uniformly for std::map / std::unordered_map and std::array / std::vector as the former is a collection of key/value pairs and the latter is collection of values...

You may want to use std::find_if instead as it gives you a little bit more flexibility on defining equality condition eg like this (c++1z approach):

#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());
}

[live demo]

Have in mind that this approach won't work as expected if you decide to search through collection like std::vector<std::pair<int, int>> .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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