Search code examples
c++templatesdictionarycomparatorconstructorargument

map Comparison Constructor Parameter


Is there a reason why I cannot pass a comparison functor to a map as a constructor argument:

map<int, string, greater<int>> foo;
//map<int, string> foo(greater<int>()); Doesn't work

Or why I cannot pass a lambda without providing my own comparison type:

map<int, string, function<bool(const int&, const int&)>> bar([](const int& lhs, const int& rhs){ return lhs > rhs; });
//map<int, string> bar([](const int& lhs, const int& rhs){ return lhs > rhs; }); Doesn't work

I'd like to just be able to declare map<int, string> and construct it with a comparator. Why can't I?

[Live Example]


Solution

  • This question stems from a misconception. To clear that up:

    Functors are objects not functions

    Trying to assign a function pointer or a lambda to an object doesn't make any sense. So this cannot be done: map<int, string> bar([](const int& lhs, const int& rhs){ return lhs > rhs; }); The way to define a map which takes a function pointer or lambda is to use the template arguments from the question: map<int, string, function<bool(const int&, const int&)>>

    Halfway between the two ill-conceived options in the question is another misconception: map<int, string, [](const int& lhs, const int& rhs){ return lhs > rhs; }> Doesn't work because the comparator template argument is the type of a member of map, not the intialization value. So a map using a function pointer or lambda comparator must always have that value passed to the map constructor: map<int, string, function<bool(const int&, const int&)>> bar([](const int& lhs, const int& rhs){ return lhs > rhs; }) Otherwise function<bool(const int&, const int&)>() would be used for comparisons in the map.

    This is probably already clear by now, but since functors are objects you cannot pass an unrelated object is the construction value of a completely different type of object. Calling map<int, string> foo(greater<int>()) is like calling less<int> foo = greater<int>. The only acceptable compatator constructor argument to a map whose comparator template argument is a functor is something that can be converted into an object of the functor type in the template argument: map<int, string, greater<int>> foo(greater<int>{}) This is obviously unnecessary, because if no argument was provided and the greater<int> was default constructed the same member initialization of the map would result, so map<int, string, greater<int>> is sufficent.