Say I have a struct of Item
s that I'm storing in an std::set
and sorting like so:
struct Position
{
int x;
int y;
}
struct Item
{
std::string id;
Position position;
// NOTE: only `position` should matter for equality
operator==(const Item& other)
{
return position == position;
}
};
inline bool operator<(const Item& lhs, const Item& rhs)
{
if (lhs.position.x == rhs.position.x)
{
return lhs.position.y < rhs.position.y;
}
return lhs.position.x < rhs.position.x;
}
using ItemSet = std::set<Item>;
I want to use std::equal_range
to search an ItemSet
, except I want to search by Position
. I know I could do something like:
ItemSet items;
Item tempItem;
tempItem.position = some_position;
auto result = std::equal_range(items.begin(), items.end(), tempItem);
But I would like to avoid the temporary Item
.
I tried to use boost::transform_terator
like so:
auto tr = [](const Item& item) { return item.pos; };
auto tr_begin = boost::make_transform_iterator(items.begin(), tr);
auto tr_end = boost::make_transform_iterator(items.end(), tr);
Position findme { 2, 1 };
auto result = std::equal_range(tr_begin, tr_end, findme);
But this doesn't compile for reasons I don't understand, and also even if it did work, how would I get an iterator into the original collection from result
? Or maybe there's a better way overall to do this?
Here is a test harness show the problem: http://cpp.sh/3hzsq
Any help would be appreciated!
You can use
std::set::find
with a different type to avoid constructing anItem
. Note that your set can only contain one item with a specific position.You can either make
Position
directly comparable withItem
(AddItem{} < Position{}
andPosition{} < Item{}
) or create a new proxy class:You can alternatively use a completely different comparator to make
Position
comparable withItem
.And use it like so: