1

I asked this question on stackoverflow STL passing object

I got to know that we pass objects which in tern call the compare operator in them and compare our values and gives us a result. All good.

Now in this piece of code:

class Compare {
    public:
    bool operator ()(const int &a, const int &b) { return a < b;}
};

void solve(){
    set<int, Compare> s;
    vector<int> arr = {1,4,6,3,7,2,8,588,5};    
    for(int e : arr) s.insert(e);
    for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl;
}

I get error if I do Compare() which is what I thought must be done(passing an object). Why so? How can we pass Compare?

Also in this piece of code I cannot pass a function like:

bool comp(const int &a, const int &b) { return a < b; }

void solve(){
    set<int, comp> s;
    vector<int> arr = {1,4,6,3,7,2,8,588,5};    
    for(int e : arr) s.insert(e);
    for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl;
}

Which is what I expect. Not passing functions.

Now in this piece of code:

bool comp(const int &a, const int &b) { return a < b; }

void solve(){
    vector<int> arr = {1,4,6,3,7,2,8,588,5};    
    nth_element(arr.begin(), arr.begin()+3, arr.end(), comp);
    for(int e : arr) cout << e << " "; cout << endl;
}

I am able to pass a function and there is no error. I mean what is going on? From my perspective, we should just pass objects and they will call their () overloaded operator and compare values but sometimes we are passing functions, sometimes passing objects giving error and sometimes we just pass class name. What is exactly going on in c++

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Shobhit Tewari
  • 535
  • 5
  • 20
  • Can you provide the error message for each case? – Mansoor Jun 15 '21 at 09:43
  • A lot of error like function returning function. no known conversion for argument 2 from 'Compare' to 'bool'. Etc etc but basically saying I can't compare the way I am doing it – Shobhit Tewari Jun 15 '21 at 09:48
  • 1
    the STL is a library that was the predecessor of the c++ standard library. Your title suggests that you are talking about both, the STL and the standard library, but I think you mean the standard library – 463035818_is_not_an_ai Jun 15 '21 at 09:48

3 Answers3

3

Second template parameter of std::set is a type.

You might use function pointer:

bool comp(const int &a, const int &b) { return a < b; }

std::set<int, bool (*)(const int &, const int &)> s(comp);
Jarod42
  • 203,559
  • 14
  • 181
  • 302
2

operator() must be const. That's the API.

class Compare {
    public:
    bool operator ()(const int &a, const int &b) const { return a < b; }
}
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
  • Even if it's not const, it does not give error. It gives me error in set if I do Compare() instead of Compare. Also the semicolon I am saying that the for loop scope ends here and I am writing a fresh line. I just did it like this as I was focusing on learning,. – Shobhit Tewari Jun 15 '21 at 09:54
  • @ShobhitTewari how do you use `Compare()`? You can't do `set`, that wouldn't work – Aykhan Hagverdili Jun 15 '21 at 09:57
  • So in set class is it like, whatever type I passed it will create object and then call the overloaded function? If yes I got it. Inside set class somewhere for Compare c; c(a, b) – Shobhit Tewari Jun 15 '21 at 09:58
  • @ShobhitTewari: You may want to get a good C++ book. `std::set` is a _class template_. It is instantiated with a _value type_ and optionally with a comparison type that provides the set order. That's two _types_. Some template accept non-type template arguments, but ` std::set` only takes types. – MSalters Jun 15 '21 at 10:08
  • Yeah I got it. Thanks. It is clear now. The question is which answer to accept as all are correct. – Shobhit Tewari Jun 15 '21 at 10:14
2

In the first code snippet the compiler issues an error because you was using an object Compare() as the type template argument instead of the type Compare.

If you will write for example

#include <iostream>
#include <vector>
#include <set>

using namespace std;

class Compare {
    public:
    bool operator ()(const int &a, const int &b) const { return a < b;}
};

int main() 
{
    set<int, Compare> s( ( Compare() ) );
    
    vector<int> arr = {1,4,6,3,7,2,8,588,5};    
    for(int e : arr) s.insert(e);
    for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl;   

    return 0;
}

then the program compiles successfully and its output is

588 8 7 6 5 4 3 2 1 

That is as the second type template argument of the class template std::set you need to use the type specifier Compare. But if you want to specify the argument of the constructor you need to use an object of the type of the template argument.

The same problem exists for the second code snippet. You need to write like it is shown in this demonstrative program.

#include <iostream>
#include <vector>
#include <set>

using namespace std;

bool comp(const int &a, const int &b) { return a < b; }

int main() 
{
    set<int, bool ( * )( const int &, const int & )> s( comp );
    
    vector<int> arr = {1,4,6,3,7,2,8,588,5};    
    for(int e : arr) s.insert(e);
    for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl;   return 0;
}

The program output is the same as shown above.

Pay attention to that the class template std::set is declared like

template <class Key, class Compare = less<Key>, 
          class Allocator = allocator<Key> >
class set;

So if you specified explicitly the second template argument (instead of using by default the function object std::less<Key>) then you need to provide a corresponding object of this type in a constructor of the class template std::set.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • First one is correct. But if I pass Compare() instead of Compare I get an error – Shobhit Tewari Jun 15 '21 at 09:52
  • @ShobhitTewari: `Compare` is a (class) type. `Compare( )` is a temporary object of `Compare` type, created by calling the default constructor `Compare::Compare( )`. This ctor does nothing, and is implicitly defined by the compiler for you. – MSalters Jun 15 '21 at 09:55
  • @ShobhitTewari The template argument specifies a type template argument. The argument of the constructor std::set is an object of the type template argument. – Vlad from Moscow Jun 15 '21 at 09:58
  • @MSalters `Compare()` could also be a type (a function type taking no arguments, returning `Compare`). It's not clear how OP uses it. – Aykhan Hagverdili Jun 15 '21 at 09:58
  • @AyxanHaqverdili: OP literally wrote `class Compare { ...` – MSalters Jun 15 '21 at 10:04
  • What's the usage of `set s( ( Compare() ) );`? `set s;` is enough, please correct me if I'm wrong – Jabberwocky Jun 15 '21 at 10:20
  • @Jabberwocky I was mistaken. I updated the post. The argument is used to show the difference between a type and an object of the type. – Vlad from Moscow Jun 15 '21 at 10:24