问题
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