嵌套地图的比较器

huangapple go评论59阅读模式
英文:

comparator for nested map

问题

我有一个包含另一个地图作为值的地图。

外部地图包含字符串名称/自定义类(在此示例中,我以名称为例),内部地图包含日期时间和值。

我希望对外部地图运行CompareNames,对内部地图运行CompareDateTime。在结构体A的MyMap初始化列表中传递比较器时,我能否请得到一些帮助,看我在做什么错误。

#include <iostream>
#include <map>
#include <locale>
#include <string>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>

enum class ComparePolicy
{
    custom1,
    custom2
};

struct CompareNames
{
    explicit CompareNames(ComparePolicy policy)
        : policy(policy)
    {}

    template <typename T>
    bool operator()(const T& lhs, const T& rhs) const
    {
        if (policy == ComparePolicy::custom1)
        {
            return lhs < rhs;
        }
        else
        {
            return lhs > rhs;
        }
    }

    ComparePolicy policy;
};

struct CompareDateTime
{
    explicit CompareDateTime(ComparePolicy policy)
        : policy(policy)
    {}

    template <typename T>
    bool operator()(const T& lhs, const T& rhs) const
    {
        const boost::posix_time::ptime timelhs =
            boost::posix_time::time_from_string(lhs);
        const boost::posix_time::ptime timerhs =
            boost::posix_time::time_from_string(rhs);
        if (policy == ComparePolicy::custom1)
        {
            return timelhs < timerhs;
        }
        else
        {
            return timelhs > timerhs;
        }
    }

    ComparePolicy policy;
};

struct A
{
    explicit A(ComparePolicy dateTime, ComparePolicy names)
        : MyMap(CompareNames(names), CompareDateTime(dateTime))
    {}
    
    void fillMe()
    {
        MyMap["alpha"]["1981-08-20 08:05:00"] = 1;
        MyMap["alpha"]["1981-08-20 10:05:00"] = 1;
        MyMap["alpha"]["1981-08-20 09:05:00"] = 1;
        MyMap["gamma"]["1981-08-20 08:05:00"] = 1;
        MyMap["gamma"]["1981-08-20 10:05:00"] = 1;
        MyMap["gamma"]["1981-08-20 09:05:00"] = 1;    
        MyMap["beta"]["1981-08-20 08:05:00"] = 1;
        MyMap["beta"]["1981-08-20 10:05:00"] = 1;
        MyMap["beta"]["1981-08-20 09:05:00"] = 1;
    }
    
    void printMe()
    {
        for (auto& item : MyMap)
        {
            for (auto& entry : item.second)
            {
                std::cout << item.first << "  :  " << entry.first << " :  " << entry.second << std::endl;
            }
        }
    }
    
    std::map<std::string, std::map<std::string, int, CompareDateTime>, CompareNames> MyMap;
};


int main()
{
    A test(ComparePolicy::custom1, ComparePolicy::custom2);
    test.fillMe();
    test.printMe();

    return 0;
}

colliru链接: http://coliru.stacked-crooked.com/a/2bdfbf3bd96ed17e

英文:

I have a map which contains another map as value.

Outer map contains string names/custom class (in this example i took name as example), inside map contain datetime and value.

I want CompareNames to be running for outer map and CompareDateTime to be running for inside map. Can i please get some help with what am i doing wrong while passing the comparators to the MyMap initializer list in struct A.

#include &lt;iostream&gt;
#include &lt;map&gt;
#include &lt;locale&gt;
#include &lt;string&gt;
#include &lt;boost/date_time/posix_time/posix_time.hpp&gt;
#include &lt;boost/date_time/posix_time/posix_time_io.hpp&gt;
enum class ComparePoilicy
{
custom1,
custom2
};
struct CompareNames
{
explicit CompareNames(ComparePoilicy policy)
: policy(policy)
{}
template &lt;typename T&gt;
bool operator()(const T&amp; lhs, const T&amp; rhs) const
{
if (policy == ComparePoilicy::custom1)
{
return lhs &lt; rhs;
}
else
{
return lhs &gt; rhs;
}
}
ComparePoilicy policy;
};
struct CompareDateTime
{
explicit CompareDateTime(ComparePoilicy policy)
: policy(policy)
{}
template &lt;typename T&gt;
bool operator()(const T&amp; lhs, const T&amp; rhs) const
{
const boost::posix_time::ptime timelhs =
boost::posix_time::time_from_string(lhs);
const boost::posix_time::ptime timerhs =
boost::posix_time::time_from_string(rhs);
if (policy == ComparePoilicy::custom1)
{
return timelhs &lt; timerhs;
}
else
{
return timelhs &gt; timerhs;
}
}
ComparePoilicy policy;
};
struct A
{
explicit A(ComparePoilicy dateTime, ComparePoilicy names)
: MyMap( CompareNames(names), CompareDateTime(dateTime))
{}
void fillMe()
{
MyMap[&quot;alpha&quot;][&quot;1981-08-20 08:05:00&quot;] = 1;
MyMap[&quot;alpha&quot;][&quot;1981-08-20 10:05:00&quot;] = 1;
MyMap[&quot;alpha&quot;][&quot;1981-08-20 09:05:00&quot;] = 1;
MyMap[&quot;gamma&quot;][&quot;1981-08-20 08:05:00&quot;] = 1;
MyMap[&quot;gamma&quot;][&quot;1981-08-20 10:05:00&quot;] = 1;
MyMap[&quot;gamma&quot;][&quot;1981-08-20 09:05:00&quot;] = 1;    
MyMap[&quot;beta&quot;][&quot;1981-08-20 08:05:00&quot;] = 1;
MyMap[&quot;beta&quot;][&quot;1981-08-20 10:05:00&quot;] = 1;
MyMap[&quot;beta&quot;][&quot;1981-08-20 09:05:00&quot;] = 1;
}
void printMe()
{
for (auto&amp; item : MyMap)
{
for (auto&amp; entry : item.second)
{
std::cout &lt;&lt; item.first &lt;&lt; &quot;  :  &quot; &lt;&lt; entry.first &lt;&lt; &quot; :  &quot; &lt;&lt; entry.second &lt;&lt; std::endl;
}
}
}
std::map&lt;std::string, std::map&lt;std::string, int, CompareDateTime&gt;, CompareNames&gt; MyMap;
};
int main()
{
A test(ComparePoilicy::custom1, ComparePoilicy::custom2);
test.fillMe();
test.printMe();
return 0;
}

colliru link: http://coliru.stacked-crooked.com/a/2bdfbf3bd96ed17e

i tried searching for simillar issues, reading https://en.cppreference.com/w/cpp/container/map/map and trying to get the solution and playing with the initializer list in struct A.

答案1

得分: 1

简而言之,要使用std::map::operator[],映射类型必须是可默认构造的,并且您的std::map使用的比较器不能是默认构造的。

您可以通过避免需要映射类型是可默认构造的成员函数来解决此问题:

struct A {
    explicit A(ComparePoilicy dateTime, ComparePoilicy names) :
        MyMap(CompareNames(names)),
        m_dateTime(dateTime) // 存储用于创建内部映射的日期时间比较器
    {}

    // 用于插入具有正确初始化比较器的值的辅助函数
    void add_one(const std::string& key1, const std::string& key2, int val) {
        if (not MyMap.contains(key1)) {
            MyMap.emplace(key1,
                          std::map<std::string, int, CompareDateTime>
                              (CompareDateTime(m_dateTime)));    
        }
        // 使用std::map::at是避免问题的一种方法:
        MyMap.at(key1).emplace(key2, val);
    }

    void fillMe() {
        // 使用辅助函数:
        add_one("alpha", "1981-08-20 08:05:00", 1);
        add_one("beta", "1981-08-20 08:05:00", 1);
        add_one("gamma", "1981-08-20 08:05:00", 1);
    }

    std::map<std::string,
             std::map<std::string, int, CompareDateTime>, CompareNames> MyMap;
    // 用于存储内部映射的比较器参数:
    ComparePoilicy m_dateTime;
};

演示链接

英文:

In short, to use std::map::operator[], the mapped type must be default constructible and your std::map uses a comparator that is not.

You can work around it by a avoiding member functions that require the mapped type to be default constructible:

struct A {
    explicit A(ComparePoilicy dateTime, ComparePoilicy names) :
        MyMap(CompareNames(names)),
        m_dateTime(dateTime) // store for when inner maps are to be created
    {}

    // a helper function to insert values with a properly initialized comparator
    void add_one(const std::string&amp; key1, const std::string&amp; key2, int val) {
        if(not MyMap.contains(key1)) {
            MyMap.emplace(key1,
                          std::map&lt;std::string, int, CompareDateTime&gt;
                              (CompareDateTime(m_dateTime)));    
        }
        // using std::map::at is one way to avoid the problem:
        MyMap.at(key1).emplace(key2, val);
    }

    void fillMe() {
        // using the helper function:
        add_one(&quot;alpha&quot;, &quot;1981-08-20 08:05:00&quot;, 1);
        add_one(&quot;beta&quot;, &quot;1981-08-20 08:05:00&quot;, 1);
        add_one(&quot;gamma&quot;, &quot;1981-08-20 08:05:00&quot;, 1);
    }

    std::map&lt;std::string,
             std::map&lt;std::string, int, CompareDateTime&gt;, CompareNames&gt; MyMap;
    // to store the comparator argument for the inner maps:
    ComparePoilicy m_dateTime;
};

Demo

huangapple
  • 本文由 发表于 2023年2月7日 03:43:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75365857.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定