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...
Related
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");
}
I'm new to C++ and have had some help with my program to compare two XML files. This is the code I have:
#include "pugixml.hpp"
#include <iostream>
#include <unordered_map>
int main() {
pugi::xml_document doca, docb;
std::map<string, pugi::xml_node> mapa, mapb;
if (!doca.load_file("a.xml") || !docb.load_file("b.xml"))
return 1;
for (auto& node: doca.child("site_entries").children("entry")) {
const char* id = node.child_value("id");
mapa[new std::string(id, strlen(id))] = node;
}
for (auto& node: docb.child("site_entries").children("entry"))
const char* idcs = node.child_value("id");
std::string id = new std::string(idcs, strlen(idcs));
if (!mapa.erase(id)) {
mapb[id] = node;
}
}
}
I seem to get a lot of errors when I try and compile it.
The first one I get is this:
src/main.cpp:10:14: error: unknown type name 'string'; did you mean 'std::string'?
std::map<string, pugi::xml_node> mapa, mapb;
~~~~~^~~
From what I understand, I have specified it correctly. Should I change it as it requests or is something else a-miss?
You need to include the string library in order to use std::string.
Since you mentioned a lot of errors, I suspect you forgot to include <cstring> in order to use strlen().
#include <string>
#include <cstring>
You have to include the string library:
#include <string>
Use the following way:
std::string varName = "var value";
I'm using Clion IDE and it worked for me.
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;
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 "
Say there is a list of integers [1,2,3,4,5] and a map function that multiplies each element with 10 and returns modified list as [10,20,30,40,50] , with out modifying the original list.
How this can be done efficiently in c++.
Here's an example:
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int multiply(int);
int main() {
vector<int> source;
for(int i = 1; i <= 5; i++) {
source.push_back(i);
}
vector<int> result;
result.resize(source.size());
transform(source.begin(), source.end(), result.begin(), multiply);
for(vector<int>::iterator it = result.begin(); it != result.end(); ++it) {
cout << *it << endl;
}
}
int multiply(int value) {
return value * 10;
}
Along the lines of #darids answer, but C++03 (current at the time of original post):
#include <vector>
#include <algorithm>
#include <functional>
std::vector<int> src;
std::vector<int> dst;
std::transform(src.begin(), src.end(),
std::back_inserter(dst),
std::bind1st(std::multiplies<int>(), 10));
If you can use it, probably the best idea is to use a function in the Standard Template Library.
For example, you might want to check out for_each or transform, which basically do just that.
I only post this to illustrate using a functor in transform rather than a global function:
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
struct MulBy : public std::unary_function<int, int>
{
MulBy(int v) : v_(v) {}
int operator()(int lhs) const
{
return lhs * v_;
}
private:
int v_;
};
int main()
{
int incoming[5] = {1, 2, 3, 4, 5};
int result[5] = {0, 0, 0, 0, 0};
transform(&incoming[0], &incoming[5], &result[0], MulBy(10));
copy(&result[0], &result[5], ostream_iterator<int>(cout, " "));
return 0;
}
#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>
using namespace std;
struct MulBy : public std::unary_function<int, int>
{
MulBy(int v) : v_(v) {}
int operator()(int lhs) const
{
return lhs * v_;
}
private:
int v_;
};
int main()
{
vector<int> ListOfNumber;
ListOfNumber.push_back(1);
ListOfNumber.push_back(2);
ListOfNumber.push_back(3);
ListOfNumber.push_back(4);
ListOfNumber.push_back(5);
vector<int> ListResult;
ListResult.resize(ListOfNumber.size());
//Produces a new list
transform(ListOfNumber.begin(),ListOfNumber.end(),ListResult.begin(),MulBy(10));
copy(ListOfNumber.begin(),ListOfNumber.end(),ostream_iterator<int>(cout,"\t"));
//Modifies the original list
transform(ListOfNumber.begin(),ListOfNumber.end(),ListOfNumber.begin(),MulBy(10));
copy(ListResult.begin(),ListResult.end(),ostream_iterator<int>(cout,"\t"));
cin.get();
}
This is my implementation for an array map method, inspired directly from javascript
#include <vector>
#include <functional>
namespace wh{
namespace array{
template<typename T>
std::vector<T> map(const std::vector<T> &vectorToMap, const std::function<T(T)> &functor){
std::vector<T> ret;
for(auto &element: vectorToMap){
ret.push_back(functor(element));
}
return ret;
}
...
}
}
#include <iostream>
int main()
{
//'spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'
std::vector<std::string> words = {"spray", "limit", "elite", "exuberant", "destruction", "present", "windows", "wlol"};}
// and this is how it is used:
words = wh::array::map<std::string>(words, [](auto word){return word+"l";});
for(auto &word: words) std::cout << word << std::endl;
return 0;
}
Maybe this will be useful for someone else, still, if <algorithm> functions are a better approach, go ahead and use them.