1

In my opinion, they are the same. But in Visual Studio 2015, they are definitely different.

//Ok, work properly
multiset<int, greater<int> > ms1;
ms1.insert(10);
ms1.insert(20);

//error, why?
multiset<int> ms2(greater<int>());
ms2.insert(30);
ms2.insert(40);

I don’t know why?

Tango Xiao
  • 319
  • 3
  • 11
  • No they're not the same. What gave you the idea that they are the same? – Sam Varshavchik Oct 03 '17 at 23:56
  • No answers [here](http://en.cppreference.com/w/cpp/container/multiset)? – user0042 Oct 03 '17 at 23:56
  • 3
    @user0042: Not really, no. This question is about a lack of understanding of the difference between template arguments and function/constructor arguments. It's a core language question. It's not really about `std::multiset`, that's just the toy he happened to be playing with when this misunderstanding manifested itself. – Benjamin Lindley Oct 04 '17 at 00:00
  • 1
    `std::multiset` takes its first template parameter as a type and the second one as a compara function. You cannot put the compare function in the constructor arguments. Do you understand what a constructor is? That might give you a good hint on why this is really strange looking and should not be confused – Fureeish Oct 04 '17 at 00:03
  • @Benjamin You're probably right. – user0042 Oct 04 '17 at 00:06
  • @Fureeish: Actually, the second template parameter is also a type. It is the type of the comparison functor which you want your multiset to use. And there is a constructor which takes a function object of that type. The only thing wrong with his second example is that the function object he is passing is not of the correct type. If he passed `less()`, it would work. – Benjamin Lindley Oct 04 '17 at 00:07
  • Ahh, did not catch that. Thank you. I will leave my previous, incorrect comment since some other people might also have misunderstood that part and this is a good explanation – Fureeish Oct 04 '17 at 00:10

1 Answers1

6

For your first example:

multiset<int, greater<int> > ms1;

This says that ms1 is a std::multiset, storing int, and using a comparison functor of the type std::greater<int>. You've left out constructor arguments, so the instance of the functor is a default constructed one, exactly as if you had passed std::greater<int>{}, like this:

multiset<int, greater<int> > ms1(greater<int>{});

In your second example:

multiset<int> ms2(greater<int>());

This one is a bit tricky. There are 2 problems here. The first one relates to what is called "The Most Vexing Parse". It has been answered many times, so I will simply link to one of those answers. Most vexing parse: why doesn't A a(()); work?

So let's assume you understand that, and modify your code accordingly to this:

multiset<int> ms2(greater<int>{});
// or this
multiset<int> ms2((greater<int>()));

In this case, you've left out the type of the comparison functor, and gone with the default. The default is std::less<int>. So the above line is equivalent to this:

multiset<int, std::less<int> > ms2(greater<int>{});

What that says is that ms2 is a std::multiset, storing int, and using a comparison functor of type std::less<int>. You are then passing an instance of std::greater<int> to the constructor. std::less<int> and std::greater<int> are different types. You can't pass an instance of one to a function that is expecting an instance of the other.

Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274