Using decltype for lambda comparators

I’m trying to understand the difference in the following two cases.
In both, I introduce a comparator as a lambda function:

auto comp = [](int x, int y) { return x%2 < y%2; };

But then, if I want to use it with a sort, I can simply write

sort(vec.begin(), vec.end(), comp);

while for a class templated on a comparator, e.g. a priority_queue I need a wrapper:

priority_queue<int, decltype(comp)> my_queue;

to pass it as a template parameter.

The sort function itself is templated on a comparator class, yet it’s somehow works without a decltype. Is there an implicit conversion that works for a sort, but doesn’t work in the second case?

>Solution :

This is all about template argument deduction. The overload of std::sort that you are calling is declared as

template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );

and when you call it like

sort(vec.begin(), vec.end(), comp);

The compiler goes through the template argument deduction steps to determine what RandomIt and Compare are based of the types of the variables passed to the function.

In the case of your priority_queue you don’t get this because there are no variables to deduce types from. Because of that you have to specify the template arguments yourself.

That said, starting in C++17 we now have class template argument deduction (CTAD) and we can use the argument supplied to the constructor to deduce the template parameters of the class. For instance if you want your priority_queue to use a std::vector<int> as the underlying container and keep the order using comp then you can do that with

priority_queue my_queue(comp, std:vector<int>{});

Leave a Reply