在类中使用谓词函数的C++ std::sort

5

我希望在某个类中,按照特定的顺序对某个结构体的向量进行排序。我已经在类中编写了结构体的定义和谓词函数,并在该类的方法中使用这些结构体和函数运行了std::sort。但是编译错误发生了。gcc版本为4.0.1,操作系统为Mac OSX。代码如下:

class sample {
public:
  struct s {
    int x;
    int y;
  };

  bool cmp (struct s a, struct s b) {
    if (a.x == b.x)
      return a.y < b.y;
    else
      return a.x < b.x;
  }

  int func(void) {
    std::vector <struct s> vec;

    // ...

    sort(vec.begin(), vec.end(), cmp);  // compilation error

    // ...

    return 0;
  }
};

int main(void) {
  sample *smp = new sample();
  smp->func();
  return 0;
}

错误信息过于庞大和复杂,以下是其前两行。

sortSample.cpp:在成员函数'int sample :: func()'中:
sortSample.cpp:51:错误:类型为'sample :: s,sample :: s'的参数与'type bool(sample :: *)(sample :: s,sample :: s)'不匹配
...

除了上述方法外,还可以通过以下方式正确运行代码。

  1. class sample之外定义struct s和函数cmp()
  2. 删除函数cmp()并在struct s中定义运算符重载<

每种方法的示例代码如下。

1)

struct s {
  int x;
  int y;
};

bool cmp (struct s a, struct s b) {
  if (a.x == b.x)
    return a.y < b.y;
  else
    return a.x < b.x;
}

class sample {
// ...

2)

struct s {
  int x;
  int y;

  bool operator<(const struct s & a) const {
    if (x == a.x)
      return y < a.y;
    else
      return x < a.x;
  }
};

有人能解释一下这种行为的机制吗?为什么第一种方法会导致编译错误?
谢谢。
4个回答

13

在第一种情况下,cmp 被声明为 class sample 的成员函数,因此需要通过 this 指针调用它。由于编译器没有可用的 this 指针,所以会报错。你可以将其声明为 static 函数,因为静态函数不需要 this 指针来调用它。在第二种情况下,由于 cmp 被声明为独立函数,它的行为与静态函数相同。在第三种情况下(使用重载运算符),sort 算法会负责为向量中的每个对象调用该函数,因此它可以编译。


6
第三种可能性是使用operator():
bool operator() (const s& a, const s& b) const
{
    if (a.x == b.x)
        return a.y < b.y;
    else
        return a.x < b.x;
}

sort(vec.begin(), vec.end(), *this);

哇,这是一个很棒的技巧。谢谢!这是我唯一能够让比较运算符访问类实例成员以及要比较的两个对象的方法——这真的很有帮助,因为在我的情况下,它允许被比较的对象使用相对于64位指针的32位索引。 - Deadcode
请注意,调用sort()的这种方法会将*this的副本传递给它,而不是引用或指针,因此如果您使用这个技巧,请确保该副本仅包括谓词需要的成员 - 最好只有一个32位或64位成员(如有必要,请使用继承和转换“this”)。 - Deadcode
还要注意的是,*this 的副本不仅会传递给 sort(),而且根据使用的 STL 实现,它还会被递归地传递给 sort() 使用的实用函数。 - Deadcode

6

由于cmp与任何特定的sample实例都无关,因此将其设置为静态成员函数。


0

我认为在类外定义cmp是最好的,因为只有当你需要访问类的某些私有特性时,才将函数作为成员函数。从逻辑上讲,它应该在那里。 cmp只是一个实用函数,为类sample提供实现功能,但实际上它不需要访问私有成员。此外,它可能不会在对象上下文中调用(它的所有操作都在其参数上进行;没有在this指针上执行任何操作),也不必在类sample::cmp的上下文中调用。虽然这似乎是一个微不足道的问题,但给函数或代码一般不必要的访问权限可能是许多软件错误或设计复杂化的源头。

以上做法的另一个好处是,您对std::sort的调用将起作用,这回答了您的问题。


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