3

I have a class Parent that loads configuration data from a file and creates Child objects in a std::map. The Child objects are mapped by a const char* that is defined in the configuration file. For any given Parent, all of the children will share the same key length. So, one Parent's mapped Child objects may have 8-byte keys and another Parent's kids may use 4-byte keys.

How is it possible, either using the method described here, or using another method, to create a new std::map member object with a comparison function that depends on data only available at runtime?

Specifically, I'm trying to use memcmp(a, b, n); like the previously linked question shows, but I want n to be variable instead of fixed at 4.

If I haven't explained well enough what I'm trying to do, I'll try to put it in code. How do I write thecompareKey so that it uses childKeyLength to compare the map keys:

class Child;
class Parent {
private:
    struct compareKey {
        bool operator()(char * const a, char * const b) {
            return memcmp(a, b, childKeyLength) < 0;
        }  
    };
    std::map<const char*, Child, compareKey> children;
    size_t childKeyLength;

public:
    Parent(size_t childKeyLength)
    : childKeyLength(childKeyLength) {};
}
Community
  • 1
  • 1
Joshua Breeden
  • 1,844
  • 1
  • 16
  • 29

1 Answers1

5

If your keys are really just arbitrary binary data as your comment suggests, then perhaps what you really want is:

std::map<std::vector<char>, Child> children;

vector already has an operator< that implements a strict weak ordering, so this just works.


If something else owns the data, then I'd suggest wrapping the length into the type and comparing that:

struct Data {
    const char* p;
    size_t len;
};

struct DataComparer {
    bool operator()(Data const& lhs, Data const& rhs) const {
        int cmp = memcmp(lhs.p, rhs.p, std::min(lhs.len, rhs.len));
        return cmp < 0 || cmp == 0 && lhs.len < rhs.len;

        // or if you're feeling feisty?
        // return std::make_tuple(memcmp(lhs.p, rhs.p, std::min(lhs.len, rhs.len)), lhs.len)
        //     < std::make_tuple(0, rhs.len);
    }
};

std::map<Data, Child, DataComparer> children;

If the key length is fixed, then you can simply make that a member of the comparison object (instead of it just floating somewhere):

struct MemComparer {
    size_t length;

    bool operator()(const char* lhs, const char* rhs) const {
        return memcmp(lhs, rhs, length) < 0;
    }
};

And now the map is copyable in a reasonable way - you just have to pass the map constructor a MemComparer instance.

Barry
  • 286,269
  • 29
  • 621
  • 977