问题
Here is an illustration of my situation. I have a std::map and I want to find the first pair<key,value> where the key is any member of an equivalence class of keys.
#include <map>
struct Category
{
int foo;
int bar;
bool operator < (const Category & rhs) const;
bool operator > (const Category & rhs) const;
};
struct Key
{
Category category;
float quality;
bool operator < (const Key & rhs) const
{
if (category < rhs.category)
return true;
else if (category > rhs.category)
return false;
else
return quality < rhs.quality;
}
};
struct Value {};
typedef std::map <Key, Value> Container;
Container::iterator find_low_quality
(
Container & container,
const Category & category
)
{
return container.lower_bound (category);
}
Container::iterator find_high_quality
(
Container & container,
const Category & category
)
{
// some checks need to be done, here omitted for brevity
return --container.upper_bound (category);
}
This doesn't work because map::lower_bound and map::upper_bound only take a key_type (i.e. Key) argument. I couldn't get std::lower_bound to compile, I see it expects a LegacyForwardIterator but I'm having a hard time interpreting the spec for this.
Insofar as the Key for my map is ordered, the Key has a compatible ordering with Category, viz: k<c if and only if k.category<c, so my requirements seem to make logical sense.
In the real situation, the Key class is more complex, and separating the quality/category components (in order to use a map<category,map<quality,value>> solution) isn't really going to work, in case that's what you're thinking of.
How can I find the lower (and upper) bounds of the range of elements in my map whose keys are equivalent to some non-key value?
回答1:
C++14 introduced the concept of a transparent comparator, where it is possible to use find, lower_bound, upper_bound, ... with anything that can be compared to the key type, as long as the comparator explicitly opts in to this behavior.
In your case you'd need to add a custom comparator
struct KeyComparator {
// opt into being transparent comparator
using is_transparent = void;
bool operator()(Key const& lhs, Key const& rhs) const {
return lhs < rhs;
}
bool operator()(Key const& lhs, Category const& rhs) const {
return lhs.category < rhs;
}
bool operator()(Category const& lhs, Key const& rhs) const {
return lhs < rhs.category;
}
};
and then you need to use that in your Container
typedef std::map <Key, Value, KeyComparator> Container;
Live demo
来源:https://stackoverflow.com/questions/54052219/can-i-extend-stdmaplower-bound-to-search-on-non-key-type-arguments