Disclamer: I know, that using std::map
solves this problem, but it is not very clean to initialize.
The problem:
Imagine you have an array of large PODs which are rather expencive copy:
struct large_pod
{
size_t id;
// a lot of members
};
So one would want to use a mapping to an intermediate associative container of pointers/references to large_pod
in order to reduce algorithim complexity when searching.
std::vector<large_pod> original{};
std::vector<size_t> ids = ids_to_work_on();
// would rather have an std::set
auto queryMap = map_by<large_pod::id>(original);
for (const auto &i : ids)
{
auto& pod = queryMap.find(i); // this will not compile, because T is not the same as Key, which is large_pod
}
So I wonder, why doesn't std::set
allow to use something other than the Key
if the Compare
will compile?
struct compare_id
{
// basic case
bool operator()(const large_pod& lhs, const large_pod& rhs) const
{
return lhs.id < rhs.id;
}
// special cases
bool operator()(const large_pod& pod, size_t id) const
{
return pod.id < id;
}
bool operator()(size_t id, const large_pod& pod) const
{
return id < pod.id;
}
};
Of course, using std::map<size_t, const large_pod*>
would work, but it requires explicit initialization and introducing redundancy (map[pod.id] = &pod
);