如何在不重载 `operator()`、`std::less`、`std::greater` 的情况下为 `std::multiset` 提供自定义比较器?

Sum*_*gra 4 c++ lambda multimap custom-compare c++11

我想要一个用于以下代码的自定义比较器。但是,我不允许重载 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";
}
Run Code Online (Sandbox Code Playgroud)

编辑:使用 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;
};
Run Code Online (Sandbox Code Playgroud)

错误:

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

JeJ*_*eJo 6

我想要一个用于以下代码的自定义比较器。但是,我不能重载operator(), std::less, std::greater

我假设你不准超载operator()的的Test类,但可能是其他类的。如果是这样,请创建一个内部private函子,该函子重载operator()并且可能是别名的一部分using list = std::multiset<int, Compare>;

class Test
{
private:
    struct Compare
    {
        bool operator()(const int lhs, const int rhs) const /* noexcept */ { return lhs > rhs; }
    };

public:
    using list = std::multiset<int, Compare>;
    std::map<std::string, list> scripts;
};
Run Code Online (Sandbox Code Playgroud)

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

更新:研究了一段时间后,我发现了一个方法去哪个不工作与lambda函数。

这个想法是使用decltypeofstd::multiset自定义 lambda 比较作为std::map 脚本的键。除此之外,提供一个包装方法来将条目插入到CustomMultiList.

完整示例代码:见直播

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

// provide a lambda compare
const auto compare = [](int lhs, int rhs) noexcept { return lhs > rhs; };

class Test
{
private:
    // make a std::multi set with custom compare function  
    std::multiset<int, decltype(compare)> dummy{ compare };
    using CustomMultiList = decltype(dummy); // use the type for values of the map 
public:
    std::map<std::string, CustomMultiList> scripts{};
    // warper method to insert the `std::multilist` entries to the corresponding keys
    void emplace(const std::string& key, const int listEntry)
    {
        scripts.try_emplace(key, compare).first->second.emplace(listEntry);
    }
    // getter function for custom `std::multilist`
    const CustomMultiList& getValueOf(const std::string& key) const noexcept
    {
        static CustomMultiList defaultEmptyList{ compare };
        const auto iter = scripts.find(key);
        return iter != scripts.cend() ? iter->second : defaultEmptyList;
    }
};


int main()
{
    Test t{};
    // 1: insert using using wrapper emplace method
    t.emplace(std::string{ "Linux" }, 5);
    t.emplace(std::string{ "Linux" }, 8);
    t.emplace(std::string{ "Linux" }, 0);


    for (const auto a : t.getValueOf(std::string{ "Linux" }))
    {
        std::cout << a << '\n';
    }
    // 2: insert the `CustomMultiList` directly using `std::map::emplace`
    std::multiset<int, decltype(compare)> valueSet{ compare };
    valueSet.insert(1);
    valueSet.insert(8);
    valueSet.insert(5);
    t.scripts.emplace(std::string{ "key2" }, valueSet);

    // 3: since C++20 : use with std::map::operator[]
    t.scripts["Linux"].insert(5);
    t.scripts["Linux"].insert(8);
    t.scripts["Linux"].insert(0);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

直到 lambda 不是默认可构造和可复制的。但是, std::map::operator[]确实要求mapping_type是可 复制构造默认可构造的。因此,使用订阅运算符 of插入scripts映射的值(即 tostd::multiset<int, decltype(/*lambda compare*/)>std::map只能从 C++20 开始。