Declare a multimap with four values for a key - c++

What syntax should I use to declare a multimap with four values for a key?
I would like to add two more values from the type unsigned int after the sc_core sc_time values.
std::multimap<std::string, std::pair<sc_core::sc_time, sc_core::sc_time> >
Thanks

You can use a tuple for that:
std::tuple<key_type1, key_type2, key_typ3, key_typ4>
For example:
#include <map>
#include <string>
#include <tuple>
int main(int argc, char* argv[])
{
std::map<std::tuple<int, int, float, float>, std::string> myMap; // if you meant 4 values as a key
std::map<std::string, std::tuple<int, int, float, float>> myMap2; // if you meant 4 values for each string key
return 0;
}
Also, I would like to note that when declaring a map, the template argument for the key goes first and then the value type (see here). Your post was ambiguously formulated so I didn't know if the four values were supposed to be the key or the value so I showed both possibilities.
EDIT: As Jamin Grey nicely pointed out you can shorten this unfathomably long type using a typedef:
typedef std::tuple<int, int, float, float> MyKeyType;
Once you've done this you can use MyKeyType in your code instead.

Related

Is it possible to insert a pair with a map type value into another map?

Tried looking this up but can't quite seem to find a detailed answer. Say I have a map:
std::map<int, string> categoryMap;
and I want to create a second map with keys and values that should only be accessed when associated with a specific key of the first map. The second map would also be similar:
std::map<int, string> itemMap;
I have attempted doing some sort of an insert function to try this out
categoryMap.insert(std::pair<int, map<int, string>>(itemValue, itemMap));
The error I receive claims that "no instance of overloaded function matches the argument list." Is there another way to approach this or is this just not possible?
Yes, it is possible but the type (template parameter) int, map<int, string> of the pair you are trying to insert does not match the map type int, string.
To be able to run your insert call:
categoryMap.insert(std::pair<int, map<int, string>>(itemValue, itemMap));
categoryMap has to be defined with the same template type as the item you are inserting, i.e.:
std::map<int, map<int, string>> categoryMap;
See it online.
#include <iostream>
#include <string>
#include<map>
using namespace std;
int main()
{
std::map<int, std::map<int, string>> categoryMap;
std::map<int, std::string> itemMap;
itemMap.insert(std::pair<int, std::string>(1, "abc"));
itemMap.insert(std::pair<int, std::string>(2, "xyz"));
categoryMap.insert(std::pair<int, std::map<int, std::string>>(1, itemMap));
}

Use find() on map of struct, get "has no member named XXX"

I defined a structure an use unsigned long long int as key to store structures in the map.
I have another function which finds the structs in the map and do some modification to the structs.
But I got error like this:
‘struct std::_Rb_tree_iterator<std::pair<const long long unsigned int, sStatics> >’ has no member named Latency
Can anyone tell me what is the error comes from?
The following is my code structure:
A.h:
#include <map>
struct sStatics;
extern std::map<unsigned long long int, sStatics> wsmStaticsMap;
A.cpp:
#include <map>
std::map<unsigned long long int, sStatics> wsmStaticsMap;
struct sStatics
{
std::string atcs;
uint32_t Latency;
std::vector<unsigned long int> lostWSM;
unsigned long int wrongOrderCount;
};
static void function_statics(){
std::map<unsigned long long int,sStatics>::iterator it;
it = wsmStaticsMap.find(atcs);
if (it != wsmStaticsMap.end()){
it->Latency++;
}
}
You have to write (it->second).Latency. It returns a key-value pair. You need to first select the value then an attribute within it.
You can check the reference
std::map::find returns
Iterator to an element with key equivalent to key. If no such element is found, past-the-end (see end()) iterator is returned.
It is a std::pair<Key, Value>, you need to use ->second to access the value.
Change
it->Latency++;
to
(it->second).Latency++;
Also, use auto to simplify
auto it = wsmStaticsMap.find(atcs);

set/access jagged map values made with map<string, boost::any>

I've been shown how to create a jagged multidimensional std::map by using boost::any.
However, I'm having trouble setting the values like in this answer.
When I use
accounts["bank"]["cash"] = 100;
gcc gives this error
error: no match for ‘operator[]’ in ‘accounts.std::map<_Key, _Tp, _Compare,
_Alloc>::operator[]<std::basic_string<char>, boost::any,
std::less<std::basic_string<char> >, std::allocator<std::pair<const
std::basic_string<char>, boost::any> > >((* & std::basic_string<char>(((const
char*)"bank"), (*(const std::allocator<char>*)(& std::allocator<char>())))))["cash"]’
How can a jagged multidimensional map created with boost::any be accessed? (If there is a better technique to do this, please show me. I only care about what works and is quick to write.)
multidimensional declaration
std::map<std::string, boost::any> accounts;
accounts["bank"] = std::map<std::string, boost::any>();
accounts["bank"]["cash"] = 100;
json-spirit
I gave up and tried to use json-spirit's mObject instead since all of this seems already built in.
Funny thing is is that with the exact same notation, I get the exact same error.
std::map<std::string, boost::any> accounts;
accounts["bank"] = std::map<std::string, boost::any>();
accounts["bank"]["cash"] = 100;
Of course this cause compile time error, you put to boost::any std::map,
but compiler have no idea about this. accounts["bank"] has "boost::any" type,
and boost::any have no
int& operator[](const char *)
Read how boost::any works: http://www.boost.org/doc/libs/1_54_0/doc/html/any/s02.html
Fix is trivial:
#include <boost/any.hpp>
#include <map>
#include <string>
int main()
{
std::map<std::string, boost::any> accounts;
accounts["cash"] = 100;
accounts["bank"] = std::map<std::string, boost::any>();
boost::any_cast<std::map<std::string, boost::any> &>(accounts["bank"])["cash"] = 100;
}
How did you define your accounts map? As boris said, you need to nest two maps together in order to do what you want.
Replace the type string with boost::any
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
map<string, map<string, string>> accounts;
accounts["bank"]["cash"] = "infinity";
cout << accounts["bank"]["cash"];
return 0;
}
How does this work?
Maps are key and value pairs.
accounts["bank"] returns the value of the outermost map, which corresponds to
map<string, **map<string, string>**>
accounts["bank"]["cash"] returns the value of the innermost map, which corresponds to
map<string, map<string, **string**>>
Defining a 1 dimensional map does not allow you to do what you want, but 2 dimensional maps do.

How to sort C++ map keys with std::greater?

I'm creating a std::map<int, int> in C++ that I'd prefer to have they keys sorted from highest to lowest instead of the default sort order. My research lead me to std::greater which looked promising but when trying to use it I'm getting a compile error:
invalid type argument of unary ‘*’ (have ‘int’)
My map declaration is:
std::map<int, int, std::greater<int> > numMap;
And the error is getting thrown from this function:
void Row::addNumber(int num, int pos) {
numMap.insert(num, pos);
}
Answers to similar questions such as this include parenthesis in the declaration, i.e. std::greater() - but when I include those I get multiple errors regarding a function returning a function.
The problem – call of std::map::insert member function with invalid parameters: there are two integer values provided; but there must be std::pair<int, int>. Please see the reference: std::map::insert.
Preferable option
For convenience (just not to repeat the map type parameters), create a typedef for the map:
typedef std::map<int, int> IntMap;
The std::map has type definition for std::pair (pair representation) – std::map::value_type.
So, for example, if there is a std::map<int, int> the std::map::value_type would be std::pair<int, int>.
Use the std::map::value_type constructor (IntMap::value_type in this case):
class Row {
public:
void Row::addNumber(int num, int pos)
{
m_numMap.insert(IntMap::value_type(num, pos));
}
private:
typedef std::map<int, int> IntMap;
IntMap m_numMap;
};
Alternatives:
Use std::make_pair() function:
#include <utility>
...
void Row::addNumber(int num, int pos)
{
numMap.insert(std::make_pair(num, pos));
}
Directly use std::pair constructor:
void Row::addNumber(int num, int pos)
{
numMap.insert(std::pair<int, int>(num, pos));
}
A bit more pedantic than Sergey's answer (which also definitely works), instead Use:
typedef std::map<int, int, std::greater<int> > MyMap;
MyMap numMap;
void Row::addNumber(int num, int pos)
{
numMap.insert(MyMap::value_type(num, pos));
}
The benefit being that if you change the type of the map, you have less code to change later. And much less likely but still possible, if the implementation of std::map changes its value_type from std::pair to something else (in a future version of the stl), you are impervious to that change.

C++ - how to create a multimap with 4 variables and 4 keys

I want to create a class like below
class enumClass
{
int msdnEnum;
std::string msdnEnumString;
int localEnum;
std::string localEnumString;
}
std::set<enumClass_Objects> enums; // all msdnEnums are unique, same aplies to other three.
enums.find(given_msdnEnum)->FourthVariable;
enums.find(given_localEnum)->FirstVariable;
enums.find(given_msdnEnumStr)->anyVariable;
enums.find(given_localEnumStr)->anyVariable;
I referred boost::multiIndex. But I don't think that it helps on this case. Can anybody say the way to achieve this?
EDIT
I am not that much good in reading template classes. As for as I am concerning I didn't find any "find" methods in multiIndex. I saw only sorting out things in that example(the first basic example:link). Suggestions&advices are always welcomed
boost multiindex is exactly what you need in this case. Construct four indexes for the four keys - I guess given you guarantee that they will all be unique, make them unique indexes (I believe only one of them can be hashed_unique, but I think you can make the other three ordered_unique), and then do your searches on the each index depending on what you are searching by.
Here's a simple example using boost.multi_index:
#include <string>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
struct enumClass
{
int msdnEnum;
std::string msdnEnumString;
int localEnum;
std::string localEnumString;
};
namespace bmi = boost::multi_index;
typedef bmi::multi_index_container<
enumClass,
bmi::indexed_by<
bmi::ordered_unique<bmi::member<enumClass, int, &enumClass::msdnEnum> >,
bmi::ordered_unique<bmi::member<enumClass, std::string, &enumClass::msdnEnumString> >,
bmi::ordered_unique<bmi::member<enumClass, int, &enumClass::localEnum> >,
bmi::ordered_unique<bmi::member<enumClass, std::string, &enumClass::localEnumString> >
>
> enumClassSet;
int main()
{
enumClassSet enums;
enums.get<0>().find(/*given_msdnEnum*/); // index 0 is enumClass::msdnEnum
enums.get<1>().find(/*given_msdnEnumStr*/); // index 1 is enumClass::msdnEnumString
enums.get<2>().find(/*given_localEnum*/); // index 2 is enumClass::localEnum
enums.get<3>().find(/*given_localEnumStr*/); // index 3 is enumClass::localEnumString
}
Tag classes could be used to access the indices by name rather than ordinal index as well, usage of which would look like this:
struct byMsdnEnum;
struct byMsdnEnumStr;
struct byLocalEnum;
struct byLocalEnumStr;
typedef bmi::multi_index_container<
enumClass,
bmi::indexed_by<
bmi::ordered_unique<bmi::tag<byMsdnEnum>, bmi::member<enumClass, int, &enumClass::msdnEnum> >,
bmi::ordered_unique<bmi::tag<byMsdnEnumStr>, bmi::member<enumClass, std::string, &enumClass::msdnEnumString> >,
bmi::ordered_unique<bmi::tag<byLocalEnum>, bmi::member<enumClass, int, &enumClass::localEnum> >,
bmi::ordered_unique<bmi::tag<byLocalEnumStr>, bmi::member<enumClass, std::string, &enumClass::localEnumString> >
>
> enumClassSet;
int main()
{
enumClassSet enums;
enums.get<byMsdnEnum>().find(/*given_msdnEnum*/);
enums.get<byMsdnEnumStr>().find(/*given_msdnEnumStr*/);
enums.get<byLocalEnum>().find(/*given_localEnum*/);
enums.get<byLocalEnumStr>().find(/*given_localEnumString*/);
}
The difference between the two approaches is purely aesthetic, and of course the tag classes could be named whatever you want rather than byMsdnEnum, etc. Also note that hashed indices could be used rather than ordered indices, which would give your indices the behavior of std::unordered_map rather than std::map.
Is there a reason why you cannot use 2 maps? ( std::map< int, std::string> ). If you need to find both of the string variables by any of those two keys, then you could solve it by having a map that would pair for example msdnEnum with both strings and then have a map that would pair localEnum with msdnEnum. Than any lookup via msdnEnum would be done directly and a lookup via localEnum would first do a translation to msdnEnum and then do a direct lookup.