Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ use std::greater() in priority_queue and sort

Why the documentation for both cases says the same thing, but they are declared in an opposite way, one uses greater<int> while the other uses greater<int>(). Could anyone please shed some light on it?

The documentation priority_queue cpp library says that comp

can be Comparison object to be used to order the heap. This may be a function pointer or function object

priority_queue<int, vector<int>, greater<int>> minheap;  //works
priority_queue<int, vector<int>, greater<int>() > minheap; //why fail?

The documentation cpp library sort says the same thing, that is, comp can either be a function pointer or a function object.

sort (numbers.begin(), numbers.end(), std::greater<int>()); //works
sort (numbers.begin(), numbers.end(), std::greater<int>); //fail
like image 863
thinkdeep Avatar asked Jul 05 '19 14:07

thinkdeep


2 Answers

In this declaration

priority_queue<int, vector<int>, greater<int>> minheap; 

greater<int> is a template argument that specifiers a type and corresponds to the type template parameter class Compare of the priority_queue

template<class T, class Container = vector<T>,
class Compare = less<typename Container::value_type>>
class priority_queue;

In this statement

sort (numbers.begin(), numbers.end(), std::greater<int>());

there is used the default constructor to create a temporary object of the type greater<int>.

std::greater is a template structure

template<class T = void> struct greater;

that is its specialization provides a type.

You can use the template specializations as type specifiers in declarations. For example

std::greater<int> obj1;
std::greater<double> obj2;
std::greater<std::string> obj3;

In the first case you have to specify the type argument for the corresponding type template parameter.

In the second case you have to specify an object of the type greater<int>.

Take into account that if you will try to use the record std::greater<int>() as a template argument for the priority_queue then the compiler considers it as a function type specifier that has return type std::greater<int> and has no parameters. Because the compiler expects a type specifier as a template argument and not an expression. But specifying such a function type as a type template argument does not make sense for the priority_queue.

To make it more clear rewrite a call of std::sort the following way

std::greater<int> obj;
sort (numbers.begin(), numbers.end(), obj );

As you see here is std::greater<int> is a type specifier for the variable obj which is supplied as an argument to the function std::sort. The difference between the call above and this call

sort (numbers.begin(), numbers.end(), std::greater<int>());

is that in the last case there is created a temporary object of the type std::greater<int> like std::greater<int>().

Here is a demonstrative program

#include <iostream>
#include <functional>
#include <iterator>
#include <algorithm>

int main() 
{
    int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    for ( const auto &item : a ) std::cout << item << ' ';
    std::cout << '\n';

    std::greater<int> comp;

    //  Here is used an already created object of the type std::greater<int> 
    std::sort( std::begin( a ), std::end( a ), comp );

    for ( const auto &item : a ) std::cout << item << ' ';
    std::cout << '\n';

    //  Here is used a remporary object of the type std::less<int> 
    std::sort( std::begin( a ), std::end( a ), std::less<int>() );

    for ( const auto &item : a ) std::cout << item << ' ';
    std::cout << '\n';

    return 0;
}

The program output is

0 1 2 3 4 5 6 7 8 9 
9 8 7 6 5 4 3 2 1 0 
0 1 2 3 4 5 6 7 8 9 
like image 121
Vlad from Moscow Avatar answered Nov 18 '22 16:11

Vlad from Moscow


The third template argument for std::priority_queue is the type of the comparator.

With greater<int>() you create an instance (an object) of the greater<int> class, and you pass this instance (object) as argument instead of the type greater<int>.

For std::sort the third function argument is an actual object (or rather, anything that is callable).


Regarding the reference you link to, it's a reference of the constructor, not the std::priority_queue template itself. Constructor arguments are like function arguments, and are very different from the template arguments.

like image 44
Some programmer dude Avatar answered Nov 18 '22 15:11

Some programmer dude