std::map insert another map - c++

I followed this answer and wrote below code. But it gives below compilation error. I think it's because make_pair cannot accept another make_pair as an argument. What is the alternative then?
error: no matching function for call to ‘std::map<std::basic_string<char>, std::map<float, int>
>::insert(std::pair<std::basic_string<char>, std::pair<double, int> >)’
code below
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, std::map<float, int> > map1;
std::string string1 = "alpha";
map1.insert(std::make_pair(string1, std::make_pair(1.1, 1)));
return 0;
}

Your initializing the second half of your "pair" with something that isn't a map.
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, std::map<float, int> > map1;
std::string string1 = "alpha";
std::map<float,int> mapsub;
mapsub.insert(std::make_pair(1.1, 1));
map1.insert(std::make_pair(string1, mapsub));
return 0;
}
Or alternatively:
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, std::map<float, int> > map1;
std::string string1 = "alpha";
map1.insert(std::make_pair(string1, std::map<float,int>{std::make_pair(1.1,1)}));
return 0;
}

Alternatively you can use the [] operator as follows:
map1[string1][1.1] = 1;

Related

Map insert is ambiguous

I am trying to use boost::container::map. During inserting data, the error "insert is ambiguous" is shown.
#include <boost/container/map.hpp>
#include <string>
#include <iostream>
int main()
{
boost::container::map<std::string, int> map;
map.insert("Ram",0);
}
Your style of inserting is not correct. I provide the code:
#include <boost/container/map.hpp>
#include <string>
#include <iostream>
#include <ostream>
int main()
{
boost::container::map<std::string, int> map;
map.insert(std::pair<const std::string, int>("Ram",1));
std::cout<< map["Ram"];
return 0;
}

How to fix "non-aggregates cannot be initialized with initializer list” <map>

This works in VS2018, but not in 2008, and i'm not sure how to fix it.
#include <map>
#include <string>
int main() {
std::map<std::string, std::string> myMap = {
{"Code", "Test"},
{"Code", "Test1"},
{"Code", "Test2"},
};
}
This is the error :
Error 2 error C2552: 'myMap' : non-aggregates cannot be initialized with initializer list
VS2008 is an old compiler that doesn't support C++11 which is needed for this.
You can insert each element:
int main() {
std::map<std::string, std::string> myMap;
myMap["Code"] = "Test";
myMap["Code"] = "Test1";
myMap["Code"] = "Test2";
}
Or you can use boost:
#include "boost/assign.hpp"
int main() {
std::map<std::string, std::string> myMap = boost::assign::map_list_of
("Code", "Test")
("Code", "Test1")
("Code", "Test2");
}
Option 1: Use a compiler that supports C++11 or a later version of the standard where extended list initialisation is well-formed. (I.e. give up on VS2008)
Option 2: Write the program in C++03 (or older if necessary) compliant dialect. An example:
typedef std::map<std::string, std::string> Map;
typedef Map::value_type Pair;
Pair elements[] = {
Pair("Code", "Test"),
Pair("Code", "Test1"),
Pair("Code", "Test2"),
};
const std::size_t length = sizeof(elements)/sizeof(*elements);
Map myMap(elements, elements + length);
To fix it you have to make it C++03 compliant (this is what vs2008 supports), so basically:
#include <map>
#include <string>
int main() {
std::map<std::string, std::string> myMap;
myMap["Code0"] = "Test0";
myMap["Code1"] = "Test1";
myMap["Code2"] = "Test2";
}
Boost.Assign can greatly simplify life:
#include <boost/assign.hpp>
#include <map>
#include <string>
int main()
{
::std::map< ::std::string, ::std::string > items;
::boost::assign::insert(items)
("Code", "Test")
("Code", "Test1")
("Code", "Test2");
}

Missing constructor for initialization for map

I had some help on a previous topic, where I had to change my map to use int in combination with strings. When I have done this it gives me a different issue. This is the issue:
src/main.cpp:11:29: error: no matching constructor for initialization of
'std::map<int, std::string>'
...tagMap {{"1", "data"}, {"2", "entry"}, {"3", "id"}, {"4", "content"}};
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It seems like the issue (which I looked up on another topic) seems to allude to the fact that the issue is to do with making your constructor take const references? I don't really understand how to implement this.
#include "pugi/pugixml.hpp"
#include <iostream>
#include <string>
#include <map>
int main()
{
pugi::xml_document doca, docb;
std::map<std::string, pugi::xml_node> mapa, mapb;
std::map<int, std::string> tagMap {{"1", "data"}, {"2", "entry"}, {"3", "id"}, {"4", "content"}};
if (!doca.load_file("a.xml") || !docb.load_file("b.xml")) {
std::cout << "Can't find input files";
return 1;
}
for (auto& node: doca.child(tagMap[1]).children(tagMap[2])) {
const char* id = node.child_value(tagMap[3]);
mapa[id] = node;
}
for (auto& node: docb.child(tagMap[1]).children(tagMap[2])) {
const char* idcs = node.child_value(tagMap[3]);
if (!mapa.erase(idcs)) {
mapb[idcs] = node;
}
}
}
Any help would be appreciated.
Try sth like:
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
std::map<int, std::string> tagMap {make_pair(1, "data"), make_pair(2, "entry")};
}
Edit: The version without make_pair function is also valid:
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
std::map<int, std::string> tagMap {{1, "data"}, {2, "entry"}};
}
The only thing you need to remember is that you shouldn't rely on compiler const string literal to number cast...

Error "xxxx"does not name a type

I encountered a problem when tried compiling the following code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
map<char, int> mapDial;
mapDial['A'] = 2;
int main()
{
cout << mapDial['A'] << endl;
return 0;
}
The compiler gave me a error: 'mapDial' does not name a type error. I am new to c++ and really don't know what is going on here. Can anyone here help me to solve this? Thanks!!
You cannot execute arbitrary expressions at global scope, so
mapDial['A'] = 2;
is illegal. If you have C++11, you can do
map<char, int> mapDial {
{ 'A', 2 }
};
But if you don't, you'll have to call an initialisation function from main to set it up the way you want it. You can also look into the constructor of map that takes an iterator, and use that with an array in a function to initialise the map, e.g.
map<char, int> initMap() {
static std::pair<char, int> data[] = {
std::pair<char, int>('A', 2)
};
return map<char, int>(data, data + sizeof(data) / sizeof(*data));
}
map<char, int> mapDial = initMap();
When you declare a variable in global scope, you may only do initialization. E.g,
int a = 0;
You cannot do normal statements like:
a = 9;
So I would fix the code with:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
map<char, int> mapDial;
int main()
{
mapDial['A'] = 2;
cout << mapDial['A'] << endl;
return 0;
}
You can't have statements like mapDial['A'] = 2; at global scope. They must be inside a function.

Populate a vector with all multimap values with a given key

Given a multimap<A,B> M what's a neat way to create a vector<B> of all values in M with a specific key.
e.g given a multimap how can I get a vector of all strings mapped to the value 123?
An answer is easy, looping from lower->upper bound, but is there a neat loop-free method?
Here's the way to do it STL style :
// The following define is needed for select2nd with DinkumWare STL under VC++
#define _HAS_TRADITIONAL_STL 1
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <functional>
#include <map>
#include <iterator>
#include <iostream>
using namespace std;
void main()
{
typedef multimap<string, int> MapType;
MapType m;
vector<int> v;
// Test data
for(int i = 0; i < 10; ++i)
{
m.insert(make_pair("123", i * 2));
m.insert(make_pair("12", i));
}
MapType::iterator i = m.lower_bound("123");
MapType::iterator j = m.upper_bound("123");
transform(i, j, back_inserter(v), select2nd<MapType::value_type>());
copy(v.begin(), v.end(), ostream_iterator<int>(cout, ","));
}
Let's go lambda
given: multimap<A,B> M
requested: vector<B> (of all values in M with a specific key 'a'.)
method:
std::pair<M::iterator, M::iterator> aRange = M.equal_range('a')
std::vector<B> aVector;
std::transform(aRange.first, aRange.second,std::back_inserter(aVector), [](std::pair<A,B> element){return element.second;});
System environment:
compiler: gcc (Ubuntu 5.3.1-14ubuntu2.1) 5.3.1 20160413 (with -std=c++11)
os: ubuntu 16.04
Code example:
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <functional>
#include <iostream>
int main()
{
typedef std::multimap<std::string, int> MapType;
MapType m;
std::vector<int> v;
/// Test data
for(int i = 0; i < 10; ++i)
{
m.insert(std::make_pair("123", i * 2));
m.insert(std::make_pair("12", i));
}
std::pair<MapType::iterator,MapType::iterator> aRange = m.equal_range("123");
std::transform(aRange.first, aRange.second, std::back_inserter(v), [](std::pair<std::string,int> element){return element.second;});
for(auto & elem: v)
{
std::cout << elem << std::endl;
}
return 0;
}
You need a loop anyway. All "loop-free" methods just abstract the loop away.
#include <map>
#include <vector>
#include <algorithm>
#include <ext/functional>
using namespace std;
int main () {
multimap<int, double> mm;
mm.insert(make_pair(1, 2.2));
mm.insert(make_pair(4, 2.6));
mm.insert(make_pair(1, 9.1));
mm.insert(make_pair(1, 3.1));
vector<double> v;
transform(mm.lower_bound(1), mm.upper_bound(1),
back_inserter(v), __gnu_cxx::select2nd<pair<int, double> >());
// note: select2nd is an SGI extension.
for (vector<double>::const_iterator cit = v.begin(); cit != v.end(); ++ cit)
printf("%g, ", *cit); // verify that you've got 2.2, 9.1, 3.1
return 0;
}
template <class Key, class Val>
vector<Val>& getValues(multimap<Key, Val>& multi, Key& key)
{
typedef multimap<Key, Val>::iterator imm;
static vector<Val> vect;
static struct
{
void operator()(const pair<Key, Val>& p) const
{
vect.push_back(p.second);
}
} Push;
vect.clear();
pair<imm, imm> range = multi.equal_range(key);
for_each(range.first, range.second, Push);
return vect;
}
This is a bit contrived because of your 'no loop' requirement.
I prefer:
template <class Key, class Val>
vector<Val> getValues(multimap<Key, Val>& map, Key& key)
{
vector<Val> result;
typedef multimap<Key, Val>::iterator imm;
pair<imm, imm> range = map.equal_range(key);
for (imm i = range.first; i != range.second; ++i)
result.push_back(i->second);
return result;
}
You could initialise the vector by giving it two iterators, like this:
std::multimap<std::string, std::string> bar;
...
std::vector<pair<string,string> > foo(bar.lower_bound("123"), bar.upper_bound("123"));
but that would give you a vector of pairs (ie, with both the key and value).
Another option would be to use std::copy with something like a back_inserter, which is another way to hide the loop, but with the same downside as above.
std::copy(bar.lower_bound("123"), bar.upper_bound("123"), std::back_inserter(foo));
This would append the elements (if any) to the vector foo.
For extracting the values only, I can't think of any way but to loop over the results as I'm not aware of a standard way to get only the value out of a range.
Just some addenda to the other answers here…
std::mem_fn (from #include <functional>) can be used as a shorthand for the transform operator:
// previously we might've used this longhand
[](pair<int,string> element){return element.second;}
And we can use vector::resize and std::distance to allocate space for the vector in one go, rather than repeatedly resizing it with back_inserter.
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <functional>
#include <iterator>
#include <iostream>
using namespace std;
typedef multimap<int, string> MapType;
int main()
{
MapType multimap;
vector<string> valuesForKey123;
multimap.emplace(0, "red");
multimap.emplace(123, "hello");
multimap.emplace(123, "world");
multimap.emplace(0, "herring");
MapType::iterator lower{multimap.lower_bound(123)};
MapType::iterator upper{multimap.upper_bound(123)};
valuesForKey123.resize(distance(lower, upper));
transform(
lower,
upper,
valuesForKey123.begin(),
mem_fn(&MapType::value_type::second));
copy(
valuesForKey123.begin(),
valuesForKey123.end(),
ostream_iterator<string>(cout, " "));
}
// outputs "hello world "