C++ 使用自定义 std::set 比较器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2620862/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 00:07:44  来源:igfitidea点击:

Using custom std::set comparator

c++stl

提问by Omry Yadan

I am trying to change the default order of the items in a set of integers to be lexicographic instead of numeric, and I can't get the following to compile with g++:

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

file.cpp:

文件.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);
    ...
}

I get the following error:

我收到以下错误:

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'

what am I doing wrong?

我究竟做错了什么?

回答by Yacoby

You are using a function where as you should use a functor (a class that overloads the () operator so it can be called like a function).

您正在使用一个函数,而您应该使用函子(一个重载 () 运算符的类,因此可以像函数一样调用它)。

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();
    }
};

You then use the class name as the type parameter

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

set<int64_t, lex_compare> s;

If you want to avoid the functor boilerplate code you can also use a function pointer (assuming lex_compareis a function).

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

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

回答by diralik

1. Modern C++20 solution

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

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

We use lambda functionas comparator. As usual, comparator should return boolean value, indicating whether the element passed as first argument is considered to go before the second in the specific strict weak orderingit defines.

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

Online demo

在线演示

2. Modern C++11 solution

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

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

Before C++20 we need to pass lambda as argument to set constructor

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

Online demo

在线演示

3. Similar to first solution, but with function instead of lambda

3. 类似于第一个解决方案,但使用函数而不是 lambda

Make comparator as usual boolean function

像往常一样制作比较器布尔函数

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

Then use it, either this way:

然后以这种方式使用它:

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

Online demo

在线演示

or this way:

或者这样:

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

Online demo

在线演示

4. Old solution using struct with ()operator

4. 使用 struct 和()operator 的旧解决方案

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

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

Online demo

在线演示

5. Alternative solution: create struct from boolean function

5. 替代方案:从布尔函数创建结构体

Take boolean function

取布尔函数

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

And make struct from it using std::integral_constant

并使用它制作结构 std::integral_constant

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

Finally, use the struct as comparator

最后,使用结构体作为比较器

std::set<X, Cmp> set;

Online demo

在线演示

回答by Potatoswatter

Yacoby's answer inspires me to write an adaptor for encapsulating the functor boilerplate.

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!

Wow, I think that was worth the trouble!

哇,我认为那是值得的麻烦!

回答by Tom Whittock

You can use a function comparator without wrapping it like so:

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

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

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

which is irritating to type out every time you need a set of that type, and can cause issues if you don't create all sets with the same comparator.

每次需要该类型的集合时都输入很烦人,如果您不使用相同的比较器创建所有集合,可能会导致问题。