insert a std::initializer_list into std::map - c++

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 :) .

Related

How to build std::vector<std::string> from std::initializer_list<char const*>

What is the correct way to build an std::vector<std::string> from an std::initializer_list<char const*>? I can iterate through the initializer list and manually build up the vector as such:
std::initializer_list<char const*> values;
std::vector<std::string> vec;
for(auto v : values) {
vec.push_back(v);
}
Seems quite verbose. Suggestions?
std::vector has a constructor that accepts an iterator range as input, as long as the dereferenced values are convertible to the vector's value_type:
std::vector<std::string> vec(values.begin(), values.end());

adopt back_inserter to insert to list from map using boost iterator adopters

std::copy(map.begin(), map.end(), std::back_inserter(list)) this is what I am trying to achive.. take i->second items from map to list. Is there any boost iterator adopters that I can use ?
I thought transform_iterator will work. and this is how I was trying to do.
std::map<int, std::string> map;
std::list<std::string> list;
std::copy(
boost::make_transform_iterator(map.begin(),
boost::bind(&std::pair<int, std::string>::second, _1)),
boost::make_transform_iterator(map.end(),
boost::bind(&std::pair<int, std::string>::second, _1)),
std::back_inserter(list));
I am actually applying on std::set_intersection That doesn't take a functor as function parameter So I cannot use std::transform and pass a function. (attaching actual code)
typedef std::map<khut::point::value_type, khut::diagonal> storage_type;
storage_type repo_begining;
storage_type repo_ending;
storage_type::const_iterator lower_it = repo_begining.lower_bound(diagonal.begining().y());
storage_type::const_iterator upper_it = repo_ending.lower_bound(diagonal.ending().y());
std::list<khut::diagonal> diagonals_intersecting;
std::set_intersection(lower_it, repo_begining.end(), repo_ending.begin(), upper_it, std::back_inserter(diagonals_intersecting));
Note: I cannot use C++11
The problem is in value_type. std::map<int, std::string>::value_type is not std::pair<int, std::string> it is std::map<const int, std::string> So once I changed the code to
std::copy(
boost::make_transform_iterator(map.begin(),
boost::bind(&std::pair<const int, std::string>::second, _1)),
boost::make_transform_iterator(map.end(),
boost::bind(&std::pair<const int, std::string>::second, _1)),
std::back_inserter(list));
It worked

How can I access a specific element in a std::map with more than 2 elements?

I am trying to access a specific element out of a std::map with more than two elements. Here is an example:
std::map <int, CString, CString, CString> map;
//Initialise
map[0] = _T("stuff1"), _T("stuff2"), _T("stuff3");
//now if I just want to access stuff3 is it this:
CString str = map[0][2];
//or something more like this?
CString str = map[0]. ???
Any help would be great thanks.
edit: Thanks sorry about that, first time using maps, I was wondering why I couldn't find any information on std::map 's with more elements inside.
Have you tried to compile this? It shouldn't.
You can create only a map with exactly 1 key and 1 value for each element.
But the value can be compound, so you can write
struct ValueType {
CString v1;
CString v2;
CString v3;
}
std::map <int, ValueType> map;
and access elements like map[somekey].v3;
To insert a value in such a map, you'll have to write
ValueType strings = {"1","2","3"};
map.insert(999, strings);
Or you may create a helper function (i.e. void addToMap(std::map <int, ValueType> &map, CSting const& v1, CString const& v2, CString const& v3) ), which will fill your map in a more convenient way.
std::map <int, CString, CString, CString> map; is illegal.
Either use a std::multimap or a std::map<int,std::vector<CString> >.
I believe this what you are looking for
std::map <int, std::list<CString> > myMap;
then you'll access myMap[0], then access each element in the returned std::list<CString>

Search in vector<std::pair<int, vector<int> > >

I would like to search within a vector<std::pair<int, vector<int> > >. This won't work due to the vector parameters:
std::vector<std::pair<int, std::vector<int> > > myVec;
iterator = find(myVec.begin(), myVec.end(), i);
Search would be on the first std::pair template parameter (int), in order to get the vector associated with it.
std::vector<std::pair<int, std::vector<int> > > myVec;
This requires C++0x for the lambda expression:
typedef std::pair<int, std::vector<int>> pair_type
std::find_if(myVec.begin(), myVec.end(), [i](pair_type const& pair)
{ return pair.first == i; });
If you're not using C++0x then either roll out your own loop or use something like Boost.Phoenix/Boost.Lambda.
Or, for both cases, why not use std::map?
You could make do with the following (pretty ugly) functoid:
struct FindFirst {
FindFirst(int i) : toFind(i) { }
int toFind;
bool operator()
( const std::pair<int, std::vector<int> > &p ) {
return p.first==toFind;
}
};
using it like this ( I couldn't get bind2nd to work - that's why I used the c'tor ):
int valueToFind = 4;
std::find_if(myVec.begin(), myVec.end(), FindFirst(valueToFind));
I think what you would like is a map:
std::map< int, vector< int > > foo;
You can then add elements, search by key etc:
int key = 4; //This will be the key
vector<int> value(5, 4); //Fill some values (5 4's in this case) into the vector
foo[key]=value; //Adds the pair to the map. Alternatively;
foo.insert( make_pair(key, value) ); //Does the same thing (in this context)
Looking at the way you've done things though, you might be wanting a std::multimap (which allows multiple values to have the same key) Class docs here
You're trying to map an int to a vector of int.
So try map<int, vector<int> >.
The second template parameter of a vector is the allocator - your compiler can probably puzzle out what you wanted to say, the declaration is wrong anyway. What you probably want is some sort of map type, like iammilind suggested.

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) { ... }