如何使用std::set作为带有显式比较器成员函数的数据成员?



我正在使用c++ 17.

std::set是模板类型:

template<
class Key,
class Compare = std::less<Key>,
class Allocator = std::allocator<Key>
> class set;

可以有一个std::set作为数据成员。例如:

#include <set>
class Foo
{
std::set<size_t> someSet_;
};

还可以显式指定比较函数。例如:

#include <set>
auto compare = [](size_t index1, size_t index2) {
return index1 < index2;
};
class Foo
{
public:
Foo() : someSet_(compare)
{
}
private:
std::set<size_t, decltype(compare)> someSet_;
};
现在,假设比较函数是一个成员函数。例如:
#include <set>
#include <vector>
class Foo
{
public:
Foo() : someSet_(compare) // does not compile
{
}
private:
bool compare(size_t index1, size_t index2) const
{
return someVector_[index1] < someVector_[index2];
}
std::vector<int> someVector_;
std::set<size_t, decltype(compare)> someSet_; // does not compile
};

如上所述,最后这段代码不能编译。

如何声明和初始化someSet_来使用Foo::compare()?

如果您查看编译器生成的错误,您将看到compare不能是非静态函数。通常你用静态函数。但在你的情况下,你需要访问成员变量,在这种情况下,最好创建助手比较器对象。例如,像这样:

#include <set>
#include <vector>
class Foo
{
public:
Foo()
{
}
private:
struct comparator {
comparator(const Foo& foo) : foo_(foo) {}
bool operator()(size_t index1, size_t index2) const
{
return foo_.someVector_[index1] < foo_.someVector_[index2];
}
private:
const Foo& foo_;
};
std::vector<int> someVector_;
comparator comp_{*this};
std::set<size_t, comparator> someSet_{comp_};
};

PS:但是在这种情况下,您需要定义或删除复制/移动构造函数和赋值操作符,因为默认会错误地复制这样的比较器。

希望比较器是成员函数的唯一原因是,当它根据其所属对象的状态生成不同的结果时。但这是错误的,比较器的结果不应该改变因为你使用的集合突然有一个错误的顺序,这是不好的。因此,请确保比较器是一个完全独立的对象,具有自己的状态,并且在使用时不会改变该状态。