使用定制的 std: : set 比较器

我试图将一组整数中项目的默认顺序改为字典顺序而不是数字顺序,但是我无法使用 g + + 编译以下内容:

Cpp:

bool lex_compare(const int64_t &a, const int64_t &b)
{
stringstream s1,s2;
s1 << a;
s2 << b;
return s1.str() < s2.str();
}


void foo()
{
set<int64_t, lex_compare> s;
s.insert(1);
...
}

我得到以下错误:

error: type/value mismatch at argument 2 in template parameter list for ‘template<class _Key, class _Compare, class _Alloc> class std::set’
error:   expected a type, got ‘lex_compare’

我做错了什么?

251015 次浏览

您正在使用一个函数,而您应该使用一个函数(一个重载()操作符以便可以像函数一样调用它的类)。

struct lex_compare {
bool operator() (const int64_t& lhs, const int64_t& rhs) const {
stringstream s1, s2;
s1 << lhs;
s2 << rhs;
return s1.str() < s2.str();
}
};

然后使用类名作为类型参数

set<int64_t, lex_compare> s;

如果你想避免使用函数的样板代码,你也可以使用函数指针(假设 lex_compare是一个函数)。

set<int64_t, bool(*)(const int64_t& lhs, const int64_t& rhs)> s(&lex_compare);

Yacoby 的回答启发我编写一个用于封装函数样板的适配器。

template< class T, bool (*comp)( T const &, T const & ) >
class set_funcomp {
struct ftor {
bool operator()( T const &l, T const &r )
{ return comp( l, r ); }
};
public:
typedef std::set< T, ftor > t;
};


// usage


bool my_comparison( foo const &l, foo const &r );
set_funcomp< foo, my_comparison >::t boo; // just the way you want it!

哇哦,我觉得这一切都是值得的!

你可以使用函数比较器而不用像这样包装它:

bool comparator(const MyType &lhs, const MyType &rhs)
{
return [...];
}


std::set<MyType, bool(*)(const MyType&, const MyType&)> mySet(&comparator);

每次你需要一组这样的类型时,输出这样的类型是很烦人的,如果你不用同一个比较器创建所有的类型,就会导致问题。

1. 现代 C + + 20解决方案

auto cmp = [](int a, int b) { return ... };
std::set<int, decltype(cmp)> s;

我们使用 Lambda 函数作为比较器。通常,比较器应该返回布尔值,指示作为第一个参数传递的元素是否被认为先于它定义的特定 严格弱排序严格弱排序中的第二个参数。

在线演示

2. 现代 C + + 11解决方案

auto cmp = [](int a, int b) { return ... };
std::set<int, decltype(cmp)> s(cmp);

在 C + + 20之前,我们需要将 lambda 作为参数传递给 set 构造函数

在线演示

3. 类似于第一种解法,但是用函数代替了 lambda

像往常一样做比较布尔函数

bool cmp(int a, int b) {
return ...;
}

那就用吧,不管怎样:

std::set<int, decltype(cmp)*> s(cmp);

在线演示

或者这样:

std::set<int, decltype(&cmp)> s(&cmp);

在线演示

4. 使用带 ()运算符的 struct 的旧解决方案

struct cmp {
bool operator() (int a, int b) const {
return ...
}
};


// ...
// later
std::set<int, cmp> s;

在线演示

5. 替代解决方案: 从布尔函数创建 struct

带上布尔函数

bool cmp(int a, int b) {
return ...;
}

并使用 std::integral_constant从中构造 struct

#include <type_traits>
using Cmp = std::integral_constant<decltype(&cmp), &cmp>;

最后,使用 struct 作为比较器

std::set<X, Cmp> set;

在线演示

operator<一起使用自定义类时使用 std::less<>

如果您正在处理一组定义了 operator<的自定义类,那么您可以只使用 std::less<>

正如在 http://en.cppreference.com/w/cpp/container/set/find C + + 14中提到的,它增加了两个新的 find API:

template< class K > iterator find( const K& x );
template< class K > const_iterator find( const K& x ) const;

你可以这样做:

Main.cpp

#include <cassert>
#include <set>


class Point {
public:
// Note that there is _no_ conversion constructor,
// everything is done at the template level without
// intermediate object creation.
//Point(int x) : x(x) {}
Point(int x, int y) : x(x), y(y) {}
int x;
int y;
};
bool operator<(const Point& c, int x) { return c.x < x; }
bool operator<(int x, const Point& c) { return x < c.x; }
bool operator<(const Point& c, const Point& d) {
return c.x < d;
}


int main() {
std::set<Point, std::less<>> s;
s.insert(Point(1, -1));
s.insert(Point(2, -2));
s.insert(Point(0,  0));
s.insert(Point(3, -3));
assert(s.find(0)->y ==  0);
assert(s.find(1)->y == -1);
assert(s.find(2)->y == -2);
assert(s.find(3)->y == -3);
// Ignore 1234, find 1.
assert(s.find(Point(1, 1234))->y == -1);
}

编译并运行:

g++ -std=c++14 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

关于 std::less<>的更多信息可以在: 什么是透明比较器?找到

在 Ubuntu 16.10,g++6.2.0上测试。

struct Cmp{
bool operator()(pair<int,int> i1,pair<int,int> i2){
return (i1.first < i2.first) || ((i1.first == i2.first) && i1.second >i2.second  );
}
};
set<pair<int,int> ,Cmp> st;

演示示例程序:

// Online C++ compiler to run C++ program online
#include <iostream>
#include<set>
using namespace std;
int arr[50];


struct Cmp{
bool operator()(pair<int,int> i1,pair<int,int> i2){
return (i1.first < i2.first) || ((i1.first == i2.first) && i1.second >i2.second  );
}
};
set<pair<int,int> ,Cmp> st;


int main() {
// Write C++ code here
arr[0] = 0,arr[1] = 2,arr[2] = 4,arr[3] = 3;
st.insert({0,1});
st.insert({1,2});
st.insert({2,2});
st.insert({2,4});
set<pair<int,int>,Cmp> ::iterator itr;
for(itr = st.begin();itr!=st.end();itr++ ){
cout<<" First: " << itr->first <<" second: " <<itr->second<<endl;
}
std::cout << "Hello world!";


return 0;
}

项目产出:

First: 0 second: 1
First: 1 second: 2
First: 2 second: 4
First: 2 second: 2
Hello world!

希望这能节省你一些时间。你想知道的关于比较器的简单理论,

在 C + + 中,如果参数相等,比较器应该返回 false