如何在不重载operator(),std :: less,std :: greater的情况下为std :: multiset提供自定义比较器? [英] How to provide custom comparator for `std::multiset` without overloading `operator()`, `std::less`, `std::greater`?

查看:97
本文介绍了如何在不重载operator(),std :: less,std :: greater的情况下为std :: multiset提供自定义比较器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want a custom comparator for the following code. However, I am not allowed to overload operator(), std::less, std::greater.

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

I tried to achieve this using lambda but gcc won't allow me to use auto as a non-static member. Any other way to make this work?

#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";
}

编辑:带有lambdas

Edit: With lambdas

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


推荐答案


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

我认为您不允许超载 Test 类的operator(),但也可以是其他类的。如果是这样,请创建一个内部 private 函子,该函子将重载 operator(),并且可能是别名<$ c的一部分$ c>使用列表= std :: multiset< int,Compare> ;;

I assume that you are not allowed to overload operator() of the Test class, but could be that of other class. If so, create a internal private functor which overloads operator() and that could be part of the alias 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;
};








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

I tried to achieve these using lambdas but gcc won't allow me to use auto as a non-static member. Any other way to make this work?

更新:经过一段时间的研究,我找到了一种方法带有lambda函数的go 起作用。

Update: After researching a while, I found a way to go which does work with a lambda function.

这个想法是使用 std :: multiset ,其中 custom lambda compare 作为 std的键:: map 脚本。除此之外,提供一种包装方法,用于将条目插入 CustomMultiList

The idea is to use the decltype of std::multiset with custom lambda compare as the key of the std::map scripts. In addition to that, provide a wrapper method for inserting the entries to the CustomMultiList.

完整的示例代码:在线观看

Complete example code: (See live)

#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;
}






,直到 lambda不是默认可构造并可以复制。但是, std :: map :: operator [] 确实要求 mapped_type 复制可构造 默认可构造 。因此,将脚本映射的值插入(即<< c> std :: multiset )。 )使用预订操作符 std :: map 只能从C ++ 20开始。


Until c++20 lambda are not default constructable and copyable. But, the std::map::operator[] does requered the mapped_type to be copy constructible and default constructible. Hence the insertion to the value of the scripts map(i.e. to std::multiset<int, decltype(/*lambda compare*/)>) using subscription operator of std::map is only possible from from C++20.

这篇关于如何在不重载operator(),std :: less,std :: greater的情况下为std :: multiset提供自定义比较器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆