-1
auto cmp = [](pair<int, int> & left, pair<int, int> & right){if(left > right) return true; else return false;};
multiset<pair<int, int>, decltype(cmp)> mt(cmp);
// If I just compile the two lines above, it will work.
// But if I try to insert some elements as below, I'll get errors.
//mt.insert({0, 3});
//mt.insert({1, 1});

However, if I add const or remove the & for the two parameters of cmp, it will work.

Why can't I use a non-const reference for cmp when I try to insert elements into mt?

Yves
  • 11,597
  • 17
  • 83
  • 180

2 Answers2

2

According to cppreference, cmp must meet the requirements of Compare.

Compare's reference says:

As with any BinaryPredicate, evaluation of that expression is not allowed to call non-const member functions of the dereferenced iterators.

In order to prevent comparers to unexpectedly change the stored elements' state, you need to either use a const reference or to take the values by copy.

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • but when I just define `mt`, I can give it a function with non-const reference? – Yves Sep 02 '16 at 09:32
  • @Thomas: the comparer is not being used in the constructor of the multiset. In short, as soon as the comparer is used for the first time *(during insert)*, the compiler complains. – Vittorio Romeo Sep 02 '16 at 09:34
  • So, the comparer used in ctor for STL must be const reference or value by copy? Because I tried to use a non-const reference lambda for std::sort and it works. – Yves Sep 02 '16 at 09:40
  • `vector vec{2, 1, 3}; std::sort(vec.begin(), vec.end(), [](int & a, int & b){return a> b;});` ----- this works. – Yves Sep 02 '16 at 09:41
  • 1
    @Thomas: it depends on how the algorithm/data structure passes the elements to the lambda. `std::multiset` probably passes the elements as `const&`, while `std::sort` simply dereferences the iterators. Using non-`const` references for non-mutating algorithms is a terrible ideas however, see [this example](http://melpon.org/wandbox/permlink/RKMfIhd2rTfMoWLa). – Vittorio Romeo Sep 02 '16 at 09:46
0

The compiler thinks you could possibly change the parameters you pass to the cmp function since you have specified references for the input parameters. However the insert statement you have is passing constants which cannot be modified (and the compiler knows this). Hence the mismatch.

If you assign two variables and then pass the variables to your insert() call, does it work?

Niall
  • 30,036
  • 10
  • 99
  • 142
sxm1972
  • 722
  • 8
  • 15
  • 1
    `int a = 1, b = 2; mt1.insert(pair{a, b});` doesn't work. – Yves Sep 02 '16 at 09:23
  • The emphasis here is that the key in the set must not be modifiable during the comparison, it has little to do with the arguments of insert. – Niall Sep 02 '16 at 10:29