Reputation: 162
I'm the headmaster of a very large public school and I've been watching my kids growing up for ten years. Their basic info and test scores each year are stored as follows:
class KidInfo{
string name;
int age;
vector<int> score; //The lengths increases as my kids grows up
};
const int NUM = 100000; //Wow, that's gigantic my friend
KidInfo myKids[NUM];
Now I want to analyze these results and create their study profile. To do this I need to sort the array myKids
by their test scores in descending order each year, for ten years. I have to use std::sort
to guarentee efficincy since I'm running quite a large school.
I'm not a very skillful C++ programmer and have no idea how to handle this task. After checking the answer sort multidimensional vector by 1st column, I wrote the following code:
bool cmpByYear1(const KidInfo &k1, const KidInfo &k2){
return k1.score[0] > k2.score[0];
}
bool cmpByYear2(const KidInfo &k1, const KidInfo &k2){
return k1.score[1] > k2.score[1];
}
//And 8 similiar functions
sort(muKids, myKids + NUM, cmpByYear1);
//print Year 1...
sort(muKids, myKids + NUM, cmpByYear2);
//print Year 2, and so on...
It didn't take too long before I got bored writing a new cmpByYearN
function each year, so I'm thinking about more elegant approaches, like template:
template<int year>
bool cmpAnyYear(const KidInfo &k1, const KidInfo &k2){
return k1.score[year - 1] > k2.score[year - 1];
}
int main(){
//...
for(int year = 1; year <= 10; ++year){
sort(myKids, myKids + NUM, cmpAnyYear<year>);
}
//...
return 0;
}
Unfortunately my code got compile error with messages like
“template parameter "year": local variables cannot be used as non-type parameter...”
.
So I was thinking using a global parameter instead:
int globalYear = 1;
bool cmpAnyYear(const KidInfo &k1, const KidInfo &k2){
return k1.score[globalYear - 1] > k2.score[globalYear - 1];
}
int main(){
//...
for(; globalYear <= 10; ++globalYear){
sort(myKids, myKids + NUM, cmpAnyYear);
}
//...
return 0;
}
This time my code actually runs, but sadly it still doesn't work: It looks like the cmpAnyYear
function was already fixed when I declared globalYear = 1;
and behaved just like cmpByYear1
regardless of the subsequent changes of globalYear
. The sorting results remain unchanged from year 2.
Upvotes: 2
Views: 476
Reputation: 75727
Use a lambda which captures the year
:
int main()
{
//...
for (int year = 1; year <= 10; ++year) {
sort(myKids, myKids + NUM, [year](const KidInfo& k1, const KidInfo& k2) {
return k1.score[year - 1] > k2.score[year - 1];
});
}
//...
return 0;
}
The reason why year
as template parameter didn't work is because it has to be a compile-time constant when you call it, which is not in your for loop
.
Upvotes: 1
Reputation: 409196
You can use functor objects, like e.g.
struct cmpAnyYear
{
cmpAnyYear(int year)
: year_(year)
{}
bool operator()(KindInfo const& k1, KidInfo const& k2) const
{
return k1.score[year_ - 1] > k2.score[year_ - 1];
}
int year_;
}
int main(){
//...
for(int year = 1; year <= 10; ++year){
sort(myKids, myKids + NUM, cmpAnyYear(year));
}
//...
return 0;
}
The expression cmpAnyYear(year)
constructs a (temporary) object of the type cmpAnyYear
and passes year
as argument to the constructor. This object is the "called" as a function, which calls the cmpAnyYear::operator()
for the comparison.
Upvotes: 2