assignment operator with maps - c++

map<char *, int> sym_addr;
map<char *, int> sym_tbl;
void set_map(map<char *, int> & sym_tbl)
{
sym_addr = sym_tbl;
}
Is there any problem with the above assignment?

A better way would be to change the keys to std::string : std::map< std::string, int>
If you want to copy, pass that object by const reference:
typedef std::map< std::string, int> myMapType;
myMapType sym_addr;
myMapType sym_tbl;
void set_map(const myMapType & sym_tbl)
{
sym_addr = sym_tbl;
}
Other then that, there are no problems. map::operator= is used to copy the content of one map into another.

You should pass the argument by const reference, otherwise you prevent copying a map declared const.
Also, make sure you understand exactly what happens if you use char* as a key - the key is the address of the string, not its contents. If you want to index the map by string values, use std::string as the key.

Related

Constructing a Map With Vectors as Values

I am trying to construct a map that maps a string to a vector of unsigned integers. The way that I construct this map is as follows:
void PixelP1ROCDACSettings::getDACs(map<string,vector<unsigned int>>& dacs) const
{
dacs.clear();
dacs.insert(pair<string, vector<unsigned int> > (k_DACName_Vdd, make_vector(Vdd_, k_DACAddress_Vdd)));
dacs.insert(pair<string, vector<unsigned int> > (k_DACName_Vana,make_vector(Vana_, k_DACAddress_Vana)));
...
}
Where make_vector is defined as follows:
std::vector<unsigned int> make_vector(unsigned int DACValue,
unsigned int DACAddress) const ;
My questions are:
1) I would like to get access each individual value in my vector, I've tried to do,
dacs[key][index] but that didn't seem to work. Is there a special syntax to do this?
2) Additionally, I would like to iterate across my map, How would I do that?
Thanks in advance.
If you are using c++11 you can iterate with
for (auto& keyvaluepair : dacs) {
//keyvaluepair.first is your string
//keyvaluepair.second is your vector
}
also dacs[key][index] is the correct way to access the indexth element in the vector mapped to by key.

map of map initialization

I am trying to initialize a map of map but I am unsure what mistake I am doing. Below is the sample code.
static std::map<std::string, std::map<std::string,std::string>> _ScalingMapVolume ={
{"AA",{"busy_timeout","test"}},
{"BB",{"cache_size","10000"}}
};
The error I am getting is;
error: no match for call to ‘(std::_Select1st<std::pair<const std::basic_string<char>, std::basic_string<char> > >) (const char&)’
{"busy_timeout","test"} is not the value of a map, but a pair. You need {{"busy_timeout","test"}}.
Your code should look like this:
static std::map<std::string, std::map<std::string, std::string>> _ScalingMapVolume = {
{"AA", {{"busy_timeout", "test"}}},
{"BB", {{"cache_size", "10000"}}}
};
init = {{"AA", {"busy_timeout", "test"}}, ...}
You are missing one set of braces, since the value_type of the map is std::pair<const std::string, std::map<std::string, std::string>>. The value_type of the mapped_type is
std::pair<const std::string, std::string>. So you need to use it that way.

insert a std::initializer_list into std::map

I have a method like this:
std::map<std::string, int> container;
void myMap(std::initializer_list<std::pair<std::string, int>> input)
{
// insert 'input' into map...
}
I can call that method like this:
myMap({
{"foo", 1}
});
How I can convert my custom argument and insert into the map?
I tried:
container = input;
container(input);
But don't work because the parameter of map is only std::initializer_list and there's no std::pair there.
Thank you all.
container.insert(input.begin(), input.end());
If you want to replace the contents of the map. do container.clear(); first.
Your problem is that the value_type of std::map<std::string,int> is not
std::pair<std::string,int>. It is std::pair<const std::string, int>. Note the const on the key. This works fine:
std::map<std::string, int> container;
void myMap(std::initializer_list<std::pair<const std::string, int>> input) {
container = input;
}
If you can't change your function's signature, you have to write a loop or use std::copy to convert each input element into the value_type of the container. But I'm guessing you probably can, since it's called myMap and not otherGuysMap :) .

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.

BOOST_FOREACH & templates without typedef

When I work with BOOST_FOREACH, there isn't a problem with simple templates as vector. But when I try to iterate through map > for example I need to typedef the element type.
Is there any workaround?
There is a problem because it is a macro, and therefore cannot handle types containing commas (preprocessor doesn't know about templates).
You can also declare the variable before the loop, see documentation.
std::map<int, double> my_map;
//1)
typedef std::pair<int, double> MyPair;
BOOST_FOREACH(MyPair p, my_map) { ... }
//2)
std::pair<int, double> p;
BOOST_FOREACH(p, my_map) { ... }
Edit:
There is a further complication with std::map in particular: the value_type is not std::pair<Key, Value>, but std::pair<const Key, Value>.
Hence, if you go with the typedef, a more proper way (and the only way if you want to use a reference in the foreach loop) is to use
typedef std::pair<const int, double> MyPair;
//or
typedef std::map<int, double>::value_type MyPair;
BOOST_FOREACH(MyPair& ref, my_map) { ... }
However, that won't work if you want to use a variable declared before the loop, since you can't assign to a std::pair<const int, double> instance later (can't assign to the const field), in which case you can only use pair<int, double> as boost's manual shows.
If you need to iterate over a map, the easiest way is to use tuples, since getting the correct type in order to typedef, is troublesome. Here is how you can use tuples:
std::map<int, double> my_map;
int key;
double value;
BOOST_FOREACH(boost::tie(key, value), my_map) { ... }
Just a note, the commas will work here because parenthesis are placed around key and value. The preprocessor only understands commas and parenthesis(and c99 requires it to understand quotation marks also). So, it can't parse the <> in std::pair<int, double>. However, we can use parenthesis to help the preprocessor. For example, if we have a a function that returns a container that is called like this:
BOOST_FOREACH(int i, foo<int, int>()) { ... } //This won't compile
So, we can place parenthesis around an expression and it will help the preprocessor:
BOOST_FOREACH(int i, (foo<int, int>())) { ... } //This will compile
However, in the case of a map, we can't place parenthesis around the declaration(because its not an expression). So this won't work:
BOOST_FOREACH((std::pair<int, double> p), my_map) { ... } //This won't work
Because it will get transformed into something like this (std::pair<int, double> p) = *it, and that, of course, is incorrect C++. But using a tie will work:
BOOST_FOREACH(tie(key, value), my_map) { ... } //This will work
We just need to declare key and value outside of the loop(as shown above). Plus, it can make the loop have more meaningful names. You can write key instead of p.first, and value instead of p.second.
BOOST_FOREACH_PAIR is another option that works well in our experience:
http://lists.boost.org/Archives/boost/2009/09/156345.php
http://lists.boost.org/Archives/boost/2009/09/156366.php
This can be as simple as this:
BOOST_FOREACH(auto& p, my_map) { ... }
Using the C++11 standard, auto is like var in C#, it will do
BOOST_FOREACH(std::pair<int, double>& p, my_map) { ... }