Appending map that uses Struct as a "multikey" and std::vector as mapped value

51 views Asked by At

in code below it appends myList only for the first call of appendMyList(), and size stays 1, so can someone explain what is wrong here:

struct MyKey {
  int accValue;
  std::string name;
};

inline bool operator<(MyKey a, MyKey b){
  return a.accValue < b.accValue && a.name < b.name;
}

inline bool operator==(MyKey a, MyKey b){
  return a.accValue == b.accValue && a.name == b.name;
}

typedef std::map<MyKey, std::vector<int>> MyList;

class MyClass {
    public:
    void appendMyList(int accVal, std::string name, int element) {
        myList[MyKey{accVal, name}].push_back(element);
        cout<<endl<<"Size after"<< myList.size()<<endl;
    }

   MyList myList;
};

I saw similar post here but don't see anything wrong with my operators, so I guess it's something else?

This is how i call the function:

int main()
{
    MyClass imHere;
    int a = 1;
    std::string yaya = "name";
    for (int i = 0; i<10; i++) {
            imHere.appendMyList((++a), yaya, i);
    }

    return 0;
};
1

There are 1 answers

0
Piotr Skotnicki On BEST ANSWER

std::map does not allow for storing duplicates. However, it doesn't use operator== for checking equality of elements. It uses operator< for both -- ordering elements as well as checking equivalence.

That is, if !(a < b) && !(b < a) then std::map considers a and b equivalent, hence no more elements than one are inserted using your operator<, because name is the same in all elements, thus both (a < b) and (b < a) return false.

Instead, you should be using:

inline bool operator<(MyKey a, MyKey b) {
  return a.accValue < b.accValue || (a.accValue == b.accValue && a.name < b.name);
}

or:

inline bool operator<(MyKey a, MyKey b) {
  return std::tie(a.accValue, a.name) < std::tie(b.accValue, b.name);
}