4

我想要以下代码的自定义比较器。但是,我不允许超载 operator(), std::less, std::greater.

我尝试使用 lambda 来实现这一点,但gcc不允许我auto用作非静态成员。还有其他方法可以使这项工作吗?

#include <iostream>
#include <map>
#include <set>

class Test 
{
public:
    // bool operator () (const int lhs, const int rhs) { // not allowed
    //     return lhs > rhs;
    // };    
    using list = std::multiset<int  /*, Test*/>;
    std::map<const char*, list> scripts;
};

int main() 
{
    Test t;
    t.scripts["Linux"].insert(5);
    t.scripts["Linux"].insert(8);
    t.scripts["Linux"].insert(0);

    for (auto a : t.scripts["Linux"]) {
        std::cout << a << std::endl;
    }

    std::cout << "end";
}

编辑:使用 lambda

class Test 
{
  public:
    auto compare = [] (const int a, const int b) { return a < b;}
    using list = std::multiset<int, compare>;    //here
    std::map<const char*, list> scripts;
};

错误:

'auto' not allowed in non-static class member
 auto compare = [] (const int a, const int b) { return a < b;}
4

3 回答 3

6
于 2019-06-01T06:34:03.740 回答
3

即使您可以按照自己的方式定义 lambda,您的方法也存在问题。看一下multiset声明

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

注意每个模板参数是一个类型(使用class关键字)。现在看看你是如何定义你的列表的:

using list = std::multiset<int, compare>;
                            ^      ^
                          type   value

第一个参数很好,但第二个参数不匹配。Compare参数必须是类型,而不是对象。解决这种情况的一种一般方法是替换comparedecltype(compare),但这似乎不是您想要的(另外它对于 lambda 类型是有问题的)。您似乎想要一个默认构造list来使用compare,而不仅仅是一个相同类型的默认构造对象。

所以你需要的是一个类,它的默认构造对象operator()以一种给出你想要的顺序的方式实现。由于我们正在处理int,因此标准库为此目的提供了一些现成的类型,即std::lessstd::greater

using list = std::multiset<int, std::greater<int>>;

但是,我不能重载 operator()、std::less、std::greater。

嗯...这表明示例代码可能被过度简化了,因为不需要重载。好的,让我们假设列表是某种更难处理的类型,例如:

class I { /* Internals not important for this example. */ };
using list = std::multiset<I, ???>;

如果您被允许修改I,那么最简单的方法可能是为类型对象定义operator>(或) 。由于(or ) 使用此运算符,您可以从标准模板中获得所需的顺序,而不会重载它。operator<Istd::greaterstd::less

如果您不允许修改I,那么我认为您只能编写自己的函数对象,因为这是 lambda 不足的一种情况。幸运的是,实现函数对象的类很容易编写;lambda 在其他情况下已经取代了它们,主要是因为 lambda 语法往往更方便。

struct CompareI {
    bool operator() (const I & lhs, const I & rhs) const { return /* fill this in */; }
};
using list = std::multiset<I, CompareI>;

虽然这定义了operator(),但它不是重载。所以它应该满足给你的要求。

于 2019-06-01T14:36:20.547 回答
2

您可以在构造函数中使用比较函数的函数指针:

主文件

#include <iostream>
#include <set>

using compType=bool(*)(int lhs, int rhs);

bool custom_compare_function(int lhs, int rhs)
{
    return lhs>rhs;
}


using list = std::multiset<int,compType>;
int main() {
    list l(&custom_compare_function);
    l.insert(1);
    l.insert(4);
    l.insert(2);
    for (auto& item: l) std::cout<<item<<std::endl;
}

产生输出

$ g++ main.cpp 
$ ./a.out 
4
2
1
于 2019-05-31T19:58:20.470 回答