如何重载自定义的std::sort比较函数?

3
使用std::sort时,我如何重载正在使用的自定义比较函数?
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>

class Misc {
public:
  // Comment out the next three lines to compile without problems.
  static bool sortPair(const std::pair<int, int> &a, const std::pair<int, int> &b){
    return a.first < b.first;
  }
  static bool sortPair(const std::pair<double, std::string> &a, const std::pair<double, std::string> &b){
    return a.first < b.first;
  }
};

int main () {
  std::vector<std::pair<double, std::string> > u;
  u.push_back(std::make_pair(10.0, "ten"));
  u.push_back(std::make_pair(5.0, "five"));
  u.push_back(std::make_pair(1.0, "one"));

  std::sort(u.begin(), u.end(), Misc::sortPair);

  for (unsigned int i=0; i< u.size(); i++){
    std::cout << u.at(i).first << std::endl;
  }

  return 0;
}

我无法将其编译,因为它报错:
“unresolved overloaded function type”
我可以看到使用sortPair可能会有一些歧义,但我假设编译器能够根据与向量u相关的类型来解决这个问题。是否有一种方法可以指定要使用哪个函数/方法以消除歧义?
目前,注释掉第一个sortPair函数允许代码被编译并产生正确排序的输出。当然,这是因为它不再具有二义性。

1
为什么你比较函数的第二个参数不是 const 引用?它缺少了 & - Joe Z
要手动解决重载问题,请使用 static_cast - Siyuan Ren
你必须手动将其转换为正确的函数指针类型,以帮助编译器消除调用的歧义。 - Arne Mertz
@slaw 那你为什么不问如何正确地转换函数指针呢?;-) 我已经为你添加了一个答案。 - Arne Mertz
@ArneMertz,感谢您在下面提供了详尽的答案! - slaw
显示剩余3条评论
3个回答

4
你可以使用一个函数对象代替它:
class Misc {
  public:
    // static bool sortPair(const std::pair<int, int> &a, const std::pair<int, int> &b);
    // static bool sortPair(const std::pair<double, std::string> &a, const std::pair<double, std::string> &b);
    bool operator() (const std::pair<int, int> &a, const std::pair<int, int> &b) { // something 
        return true;
    }
    bool operator() (const std::pair<double, std::string> &a, const std::pair<double, std::string> &b) { // something 
        return true;
    }
} misc;

int main()
{
    std::vector<std::pair<double, std::string> > u;
    std::vector<std::pair<int, int> > u2;
    //Fill vector u with data
    std::sort(u.begin(), u.end(), misc);
    std::sort(u2.begin(), u2.end(), misc);
    return 0;
}

我从未考虑过你的答案,所以感谢你。但是,我正在寻找一种方法来更改 main 中的排序行,以便保持我的原始类不变。我的问题重点在于消除歧义,而不是完全替代方案。 - slaw
@slaw,正如我在编辑中指出的那样,您可以通过引用传递它,而不更改任何其他代码。 - user1508519
传递引用不会编译也不必要。相反,只需注释掉第一个sortPair函数就可以编译并按照顺序排序向量(即消除歧义)。尽管如此,仍不清楚如何在不注释第一个sortPair的情况下让代码识别要使用哪个函数。 - slaw

1

由于u是一个包含std::pair<double, std::string>类型的向量,因此您需要调用相应的比较函数。由于仅凭名称不足以区分,您需要将其转换为具有正确函数指针类型的指针,以便编译器进行消歧义。在您的情况下,它是一个接受两个对pair类型的const引用并返回bool的函数 - 因此您需要转换为函数指针类型正是这样:

bool (*)(const std::pair<int, int> &, const std::pair<int, int> &)

一起就会变成一个相当丑陋的演员阵容:

std::sort(u.begin(), u.end(), static_cast<bool (*)(const std::pair<int, int> &, const std::pair<int, int> &)>(&Misc::sortPair));

哇。

最好使用一些typedef来澄清你正在做什么:

//includes as they were...
typedef std::pair<double, std::string> dsPair; //or something more meaningful

class Misc {
public:
  //Comment out the next three lines to compile without problems
  static bool sortPair(const std::pair<int, int> &a, const std::pair<int, int> &b){
    return a.first < b.first;
  }
  static bool sortPair(dsPair const& a, dsPair const& b){
    return a.first < b.first;
  }
};

int main () {
  std::vector<dsPair> u{ 
    {10.0, "ten"},
    {5.0, "five"},
    {1.0, "one"}
  };

  /** the function pointer typedef
   * It takes a bit getting used to, but no worries, 
   * you won't have to do it THAT often:
   **/
  typedef bool(*dsPairCompFunc)(dsPair const&, dsPair const&); 

  //and now the cast is much clearer:
  std::sort(begin(u), end(u), static_cast<dsPairCompFunc>(&Misc::sortPair));

  for (auto& e : u){
    std::cout << e.first << "\n";
  }

  return 0;
}

如果您的编译器支持,我将一些旧的C++03代码更改为C++11。


在(&Misc::sortPair)中,&符号是必需的吗?通常我会省略它,这是我第一次看到在排序比较函数中使用它。 - slaw
@slaw 不需要,函数引用会隐式转换为函数指针。我只是喜欢明确地表明它是一个函数指针。 - Arne Mertz

0

自从 C++11,你也可以使用 lambda表达式 代替定义比较函数。这样,你既不需要你的 Misc 类,也不用担心函数消歧义:

int main() {
  using dbl_str_pair_t = std::pair<double, std::string>;
  std::vector<dbl_str_pair_t> u {{10.0, "ten"}, {5.0, "five"}, {1.0, "one"}};

  using int_int_pair_t = std::pair<int, int>;
  std::vector<int_int_pair_t> v {{3, 4}, {1, 5}, {2, 6}};

  std::sort(std::begin(u), std::end(u), [](const dbl_str_pair_t& a, const dbl_str_pair_t& b) {
    return a.first < b.first;
  });

  std::sort(std::begin(v), std::end(v), [](const int_int_pair_t& a, const int_int_pair_t& b) {
    return a.first < b.first;
  });

  for (auto const &p : u)
    std::cout << p.first << std::endl;

  for (auto const &p : v)
    std::cout << p.first << std::endl;

  return 0;
}

在Ideone上的代码


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接