1

I'm setting up a new project that includes a std::multimap ideally made of defined structs.

I've tried make_pair() and multimap.insert(), and that hasn't worked so far.

My code basically is:

struct myStruct {

  myStruct() {}

  myStruct(const myStruct &other) : foo(other.foo), bar(other.bar) {}

  Neighbor &operator=(const myStruct &other) {
    if (this != &other) {
      foo = other.foo;
      bar = other.bar;
    }

    return *this;
  }

  string foo;
  std::vector<int> bar;
};

std::multimap<myStruct, myStruct> myMultiMap;

myStruct myStruct1;
myStruct myStruct2;

m_neighborMap.insert(std::pair<myStruct, myStruct>{myStruct1, myStruct2});

However, when I compile my code, I get the following errors:

/Library/Developer/CommandLineTools/usr/include/c++/v1/__functional_base:55:21: error: invalid operands to binary expression ('const myStruct' and 'const myStruct')

candidate template ignored: could not match 'pair<type-parameter-0-0, type-parameter-0-1>' against 'const myStruct'
operator< (const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y)

Does anyone know how to properly initialize this pair of structs? Thanks!

David G
  • 94,763
  • 41
  • 167
  • 253
  • 6
    Looks like `myStruct` is missing the `operator<` required for strict weak ordering and placement in the map. Probably all you need to do is implement it. [Here's some help on doing that.](https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading) – user4581301 Jul 17 '19 at 22:39
  • 3
    It would simplify your code to follow Rule of Zero for `myStruct`. Also you can avoid repetition by using `std::make_pair(myStruct1, myStruct2)` – M.M Jul 17 '19 at 22:43
  • Side-note: Is there a reason you're explicitly declaring a copy constructor and copy assignment operator? C++ would already generate them for you, and by defining them, you block the implicitly defined move constructor (which would improve performance in many cases). – ShadowRanger Jul 18 '19 at 00:19

1 Answers1

1

Your myStruct to be placed in a std::multimap requires a strict-weak-ordering, thus an operator < needs to be defined.

The easiest thing to do is to use std::tie to set this up:

#include <vector>
#include <map>
#include <algorithm>
#include <string>
#include <iostream>

struct myStruct 
{
    std::string foo;
    std::vector<int> bar;


    // define an operator <
    bool operator <(const myStruct& m) const 
    {
        return std::tie(foo, bar) < std::tie(m.foo, m.bar);
    }
};

int main()
{
    //test
    myStruct m1;
    myStruct m2;
    m1.foo = "abc";
    m1.bar = std::vector<int> {1,2,3,4};
    m2.foo = "123";
    m2.bar = std::vector<int> {4,5,6,7,8};
    std::multimap<myStruct, myStruct> myMultiMap;

    //insert into map 
    myMultiMap.insert({m1, m2});
    myMultiMap.insert({m2, m1});

    // output number of entries
    std::cout << myMultiMap.size();
}

Output:

2

In addition, since std::string and std::vector are already copyable, the myStruct need not define an assignment operator and copy constructor. Thus operator = and the myStruct(constmyStruct&) need not exist (which is why they do not exist in the sample program above).

PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
  • This didn't work when using the `return std::tie(foo, bar) < std::tie(m.foo, m.bar);` line; however, I defined the `operator <` to return true and that fixed the error messages. Will this mess up adding values to the multimap? – Julia Tepper Jul 18 '19 at 18:26
  • No, it will not work by always returning `true`. What exactly did not work? The example in the answer shows no error. – PaulMcKenzie Jul 18 '19 at 22:09