【问题标题】:A function template that can sort object array with respect to any attributes可以根据任何属性对对象数组进行排序的函数模板
【发布时间】:2016-07-30 13:00:40
【问题描述】:

我是一所非常大公立学校的校长,十年来我一直看着我的孩子长大。他们每年的基本信息和考试成绩存储如下:

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];

现在我想分析这些结果并创建他们的学习资料。为此,我需要将数组myKids 按他们每年的考试成绩降序排列,十年。我必须使用std::sort 来保证效率,因为我经营着一所大型学校。

我不是一个非常熟练的 C++ 程序员,也不知道如何处理这个任务。查了sort multidimensional vector by 1st column的答案后,我写了如下代码:

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...

没过多久,我就厌倦了每年编写一个新的cmpByYearN 函数,所以我正在考虑更优雅的方法,例如模板

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;
}

不幸的是,我的代码出现了编译错误,其中包含如下消息 “template parameter "year": local variables cannot be used as non-type parameter...”.

所以我想改用 global 参数:

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;
}

这一次我的代码实际上运行,但遗憾的是它仍然没有工作:看起来cmpAnyYear 函数已经修复 > 当我声明globalYear = 1; 并表现得就像cmpByYear1 一样,而不管globalYear 的后续变化。排序结果自第 2 年起保持不变。

【问题讨论】:

    标签: c++ sorting templates multidimensional-array


    【解决方案1】:

    您可以使用 functor 对象,例如

    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;
    }
    

    表达式cmpAnyYear(year) 构造了一个cmpAnyYear 类型的(临时)对象,并将year 作为参数传递给构造函数。这个对象作为函数被“调用”,它调用cmpAnyYear::operator()进行比较。

    【讨论】:

      【解决方案2】:

      使用捕获 year 的 lambda:

      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;
      }
      

      year 作为模板参数不起作用的原因是因为当你调用它时它必须是一个编译时常量,它不在你的for loop 中。

      【讨论】:

      • 谢谢,但还是不太明白为什么 lambda 会起作用,它仍然需要局部变量 year 作为参数,对吧? “compile-time”常量是否意味着在创建比较函数时参数的值应该是固定的,并且应该在sort内部创建lambda函数,并在year之前销毁是改变了吗?希望你能帮我澄清一下
      • @Lotayou 您可能想了解更多关于lambda expressions 的信息。基本上它创建一个临时编译器生成类的临时对象,并且与我的解决方案非常相似。
      • 解释 lambdas 超出了这个问题(和网站)的范围。网上有很多解释和介绍 lambda 的资源。正如 Joachim 所说,这或多或少是他解决方案的简写。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-03
      • 1970-01-01
      • 2017-02-23
      • 2015-06-17
      • 2019-02-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多