如何将带显式成员函数比较器的std::set作为类数据成员?
使用成员函数作为std::set比较器的C++17实现方案
问题背景
我使用的是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_; };
也可以显式指定lambda作为比较函数:
#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) // 无法编译 { } 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_; // 无法编译 };
问题:如何正确声明并初始化someSet_,使其能够使用Foo::compare()成员函数作为比较器?
解决方案
方法1:用捕获this的lambda作为比较器
直接在构造函数中定义捕获当前对象指针的lambda,作为std::set的比较器,同时注意成员变量的声明顺序(someVector_要在someSet_之前):
#include <set> #include <vector> class Foo { public: Foo() : someSet_( [this](size_t index1, size_t index2) { return compare(index1, index2); } ) { } private: bool compare(size_t index1, size_t index2) const { return someVector_[index1] < someVector_[index2]; } std::vector<int> someVector_; std::set<size_t, decltype([this](size_t, size_t){return false;})> someSet_; };
或者更简洁地直接在lambda内实现逻辑,避免额外成员函数:
#include <set> #include <vector> class Foo { public: Foo() : someSet_( [this](size_t index1, size_t index2) { return someVector_[index1] < someVector_[index2]; } ) { } private: std::vector<int> someVector_; std::set<size_t, decltype([this](size_t, size_t){return false;})> someSet_; };
方法2:自定义比较器类,持有对象引用
定义一个嵌套的比较器类,它持有Foo的const引用,这样就能访问Foo的成员:
#include <set> #include <vector> class Foo { public: Foo() : someSet_(Comparator{*this}) { } private: struct Comparator { const Foo& owner; bool operator()(size_t index1, size_t index2) const { return owner.someVector_[index1] < owner.someVector_[index2]; } }; std::vector<int> someVector_; std::set<size_t, Comparator> someSet_; };
注意事项
- 非静态成员函数需要依赖对象实例才能调用,因此不能直接作为
std::set的比较器类型(decltype(compare)得到的是成员函数指针类型,而std::set需要的是可独立调用的对象类型)。 - 成员变量声明顺序很重要:
someVector_必须在someSet_之前,确保构造someSet_时someVector_已经完成初始化。
内容的提问来源于stack exchange,提问作者user1387866
相关产品推荐
相关产品推荐

