Introduction
The standard library's std::map<Key, Value> stores
std::pair<Key const, Value>. The key and value are separate
objects, which is natural when the key is extrinsic to the value, but wasteful
and awkward when the key is already a field of the value.
Consider an employee registry keyed by employee ID:
struct Employee { int id; std::string name; double salary; };
// std::map approach: id appears twice, pair is awkward to work with
std::map<int, Employee> roster;
roster.emplace(42, Employee{42, "Alice", 95000.0}); // id duplicated
auto it = roster.find(42);
it->second.name; // must go through .second
std::set<Employee, Cmp> comes closer, but requires a custom
comparator at the type level and heterogeneous lookup requires additional
machinery, all written by hand for every type.
Eggs.KeyedSet automates this pattern. A member pointer designates which field is the key; the container handles ordering, heterogeneous lookup, and all associative container requirements automatically:
eggs::keyed_set<Employee, &Employee::id> roster;
roster.insert({42, "Alice", 95000.0});
auto it = roster.find(42); // lookup by int, no Employee constructed
it->name; // direct access, no .second
Heterogeneous Lookup
keyed_set always supports heterogeneous lookup by
key_type regardless of the Compare parameter.
When Compare defines is_transparent —such as
std::less<>— additional overloads accepting any
comparable type K are also enabled:
// Default compare: lookup by key_type always works eggs::keyed_set<Employee, &Employee::id> m; m.find(42); // OK: int is key_type // Transparent compare: lookup by any K comparable to int eggs::keyed_set<Employee, &Employee::id, std::less<>> mt; mt.find(42L); // OK: long is comparable to int via std::less<>
Ordering and Custom Comparators
The third template parameter Compare is a strict-weak-ordering
binary predicate on key_type, exactly as for std::set.
It defaults to std::less<key_type>:
// Descending order by id
eggs::keyed_set<Employee, &Employee::id, std::greater<int>> desc;
// String key with case-insensitive ordering
struct ILess {
using is_transparent = void;
bool operator()(std::string const& a, std::string const& b) const;
};
eggs::keyed_set<Employee, &Employee::name, ILess> by_name;
Allocator Support
The fourth template parameter Allocator follows the same
conventions as std::set. It defaults to
std::allocator<Value>:
using MyAlloc = std::pmr::polymorphic_allocator<Employee>; eggs::keyed_set<Employee, &Employee::id, std::less<int>, MyAlloc> m(resource);


