Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
}
  • http://ideone.com/7ULUe9

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

like image 763
nodakai Avatar asked Oct 14 '25 07:10

nodakai


1 Answers

...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"

like image 80
Vittorio Romeo Avatar answered Oct 18 '25 05:10

Vittorio Romeo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!