Reputation: 47
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 <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 ComparePoilicy
{
custom1,
custom2
};
struct CompareNames
{
explicit CompareNames(ComparePoilicy policy)
: policy(policy)
{}
template <typename T>
bool operator()(const T& lhs, const T& rhs) const
{
if (policy == ComparePoilicy::custom1)
{
return lhs < rhs;
}
else
{
return lhs > rhs;
}
}
ComparePoilicy policy;
};
struct CompareDateTime
{
explicit CompareDateTime(ComparePoilicy 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 == ComparePoilicy::custom1)
{
return timelhs < timerhs;
}
else
{
return timelhs > timerhs;
}
}
ComparePoilicy policy;
};
struct A
{
explicit A(ComparePoilicy dateTime, ComparePoilicy 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(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.
Upvotes: 1
Views: 150
Reputation: 117298
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& key1, const std::string& key2, int val) {
if(not MyMap.contains(key1)) {
MyMap.emplace(key1,
std::map<std::string, int, CompareDateTime>
(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("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;
// to store the comparator argument for the inner maps:
ComparePoilicy m_dateTime;
};
Upvotes: 1