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...
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"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With