Reputation: 25462
Am a newbie in C++, and in my endeavors in learning the language I wrote a template, and is working fine, but am puzzled how the whole thing is working!
My template contains a structure that has an operator() member function that is used as a predicate to a std::sort function. The template has an argument which is pointer to a class member, this way am able to pass different class members to be used as arguments to the template.
code:
// template definition
template<typename T, string T::*mp>
struct LessThan{
inline bool operator()(const T& c1, const T& c2){
return (c1.*mp < c2.*mp);
}
};
// class definition
class Person{
public:
...
// fields I'll for sorting
string first_name;
string last_name;
};
// Somewhere in my code, create persons and fill the vector of persons
vector<Person>persons;
p1 = Person('John','Gath');
persons.push_back(p1);
...
persons.push_back(p20);
//now I want to sort my vector of persons by either frist_name or last_name
// initialize the template
LessThan<Person, &Person::first_name>lt_fname;
// my puzzle !!
std::sort(persons.begin(), persons.end(), lt_fname); //<--NOTICE, NO () when passing lt_fname
LessThan<Person, &Person::last_name>lt_lname;
std::sort(persons.begin(), persons.end(), lt_lname); // no () for lt_lname
The code compiles well and runs!
What puzzles me, is my previous version for the predicate LessThan didn't use a template, but when passing it to sort, had to use () brackets!
How does the compiler get to know how to call the operator () function?
Paul
Upvotes: 0
Views: 146
Reputation: 19118
This line:
// initialize the template
LessThan<Person, &Person::first_name> lt_fname;
does not initializes the template, but creates an instance: lt_fname
. This instace is passed to std::sort
. You could also do:
std::sort(persons.begin(), persons.end(), LessThan<Person, &Person::first_name>());
This time you instantiating the template on the fly, passing a temporary to the sort function.
EDIT: Sort might work like this:
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp )
{
// assuming RandomIt a, b are two valid items, comp is called:
auto aIsLess = comp(a, b); // it uses the operator() of `Compare`
}
Upvotes: 3
Reputation: 33116
That operator()
is the function call operator. This functionality lets you treat an object as if it were a function.
How does the compiler get to know how to call the operator () function?
The compiler knows that your lt_lname
is an object rather than the name of a function. Even if you did have a function named lt_name
, your declaration of lt_name
hides that name. The only other option is to use the object's function call operator.
The compiler doesn't "get to know this". It has to do this to be compliant with this standard.
Update
There are two versions of std::sort
, one that takes two arguments that specify the range to be sorted, and another that takes an extra argument that specifies the comparison function (or functor).
The two argument version of sort uses the less than operator to compare objects. Since operator<
can overloaded, defining operator<
for a class provides one way of sorting a collection of instances of that class.
The three argument version takes a function (or function object) to be called in lieu of less than. Why would you do this? There are many reasons. Just a couple: Perhaps the authors of the class in question didn't define the less than operator for the class, and you can't change that class. Or perhaps you want to change the meaning of less than, depending on context. Sometimes you want to sort a collection by creation date, other times by date of last change, other times by name.
Upvotes: 1