0

Actual Problem: I named my function 'sort', and it called sort without specifying std, and now I feel dumb.

Solution: Rename my function and explicitly invoke std::sort from now on (like everyone but my professors advise me to do).

I'm trying to figure out std::sort by sorting a vector(cat) of class (Song) pointers based upon strings in that class.

I'm specifically trying to adapt this solution std::sort() on a vector of Class pointers, but without success.

The best I've been able to come up with is:

void Catalog::sort()
{
       sort(cat.begin(), cat.end(), compareTitle );
       return;
}
bool compareTitle(Song* a, Song* b)
{
        return(a->getTitle().compare(b->getTitle()) < 0);
}

Here compareTitle is not a class function. Compiler returns

catalog.cpp: In member function ‘void Catalog::sort()’:
catalog.cpp:62:44: error: no matching function for call to ‘Catalog::sort(std::vector<Song*>::iterator, std::vector<Song*>::iterator, bool (&)(Song*, Song*))’
   62 |  sort(cat.begin(), cat.end(), compareTitle );
      |                                            ^
catalog.cpp:59:6: note: candidate: ‘void Catalog::sort()’
   59 | void Catalog::sort()
      |      ^~~~~~~
catalog.cpp:59:6: note:   candidate expects 0 arguments, 3 provided

I have also tried

void Catalog::sort()
{
      sort(cat.begin(), cat.end(), [](Song* a, Song* b){
           return(a->getTitle().compare(b->getTitle()) < 0);
           });
        return;
}

Which gives me

catalog.cpp: In member function ‘void Catalog::sort()’:
catalog.cpp:66:7: error: no matching function for call to ‘Catalog::sort(std::vector<Song*>::iterator, std::vector<Song*>::iterator, Catalog::sort()::<lambda(Song*, Song*)>)’
   66 |     } );
      |       ^
catalog.cpp:59:6: note: candidate: ‘void Catalog::sort()’
   59 | void Catalog::sort()
      |      ^~~~~~~
catalog.cpp:59:6: note:   candidate expects 0 arguments, 3 provided

Any advice is appreciated; my searches have not been fruitful.

2 Answers2

3

You are struggling with how name lookup works. In Catalog::sort, when you use the non-qualified sort, the compiler comes up with Catalog::sort again - the member functions tries to calls itself. But as the function signature doesn't match, the compiler complains.

You can fix this by explicitly prefixing your call, i.e.

std::sort(cat.begin(), cat.end(),
    [](const Song *lhs, const Song *rhs) { /* ... */ });

Note that the lambda here is the way to go, passing a member function pointer (as in your first example) won't work like this.

Last, make sure that the <algorithm> header is included.

lubgr
  • 37,368
  • 3
  • 66
  • 117
2

In both cases, you want to call std::sort(), but you making a call that doesn't qualify which sort() you want, so the compiler sees the nearest sort() is Catalog::sort() and tries to call it again, but fails since the parameters do not match.

Put std:: in front of the call, eg:

void Catalog::sort()
{
    std::sort(...);
}

That being said, in both examples, whether you use a function or a lambda for your std::sort() predicate, its return statement can be simplified to this:

return a->getTitle() < b->getTitle();

The predicate is expected to return true if the 1st parameter is "less than" the 2nd parameter. Assuming getTitle() returns a std::string, its native operator< returns that exact result for you. There is no need to call compare() manually.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770