C++ using std::accumulate to generate a map<int,int> - c++

I have a problem creating a std::map<int, int> from a vector of pointers, called files. Each pointer points to an object with three member variables, one of which is size of type int. The key of the map would be the size and the value would be the number of objects which have the same size.
Do NOT waste your time on the second one! It is the next step in my program and I have figured it out already, I think. For initialization of the map I am using std::accumulate, because it returns a value. I am using std::tr1::shared_ptr for the pointers and a lambda expression for the predicate function. I am having problems with compilation.
Here's the code snippet:
map<int,int>* sizes = new map<int,int>();
sizes = accumulate(files.begin(), files.end(),sizes,
[&sizes](map<int,int> acc, shared_ptr<CFileType>& obj)
{
return sizes->insert(pair<int,int>(obj->getSize(),0));
});
Here's the error:
error C2664: 'std::pair<_Ty1,_Ty2> `anonymous-namespace'::::operator ()(std::map<_Kty,_Ty>,std::tr1::shared_ptr &) const' : cannot convert parameter 1 from 'std::map<_Kty,_Ty> ' to 'std::map<_Kty,_Ty>'
I am not very sure what to pass to the lambda function. I have tried with pair<int, int>, but it didn't work. Also, I must mention that this map is returned to another function, so it has to be a pointer.
Any help from you would be appreciated. Thanks!
UPDATE:
Problem solved, here is the solution:
map<int,int>* sizes = accumulate(files.begin(), files.end(), new map<int,int>(),
[](map<int,int>* acc, shared_ptr<CFileType>& obj)->map<int,int>*
{
acc->insert(pair<int,int>(obj->getSize(),0));
return acc;
});

The error message is that you have a type mismatch between the two kinds of std::maps. It looks like the error is in the code that calls the lambda, which apparently passes the wrong thing for the acc parameter. The good news is that the lambda, as posted, never actually uses the acc parameter.

Related

Why can't I insert objects into a map in c++

So i have a function that is supposed to return a following map:
map<MyObj*, Datastruct>
While trying to insert object from a list which contains said objects:
for(auto element: myList){
Datastruct str;
str.property1 = element.property1;
str.property2 = element.property2;
saidMap.insert(element.PointerToMyObj, str);
}
Objects in myList contain a pointer to myObj and some properties i need to move from list to a map. Having executed this code in a function below:
map<MyObj*, Datastruct> listToMap = convertList(myList);
I get yelled at by the compiler that:
"no matching function to call to 'std::map::insert(MyObj*&, Datastruct&)"
Here i am helpless. I don't know why compiler would show that i am trying to pass a reference to the function if element in myList(see above) contains
MyObj *PointerToMyObj;
which, the way i see it, is a correct type to pass to the insert function right?
I also tried with
std::make_pair
whereupon compiler yells at me for trying to insert a pair into a
map<MyObj*, Datastruct>.
I am utterly lost. Could someone explain to me what i am doing wrong?
The map's value type is not
std::pair<MyObj*, Datastruct>
but
std::pair<MyObj* const, Datastruct>
Presumably you hardcoded the pair type somewhere, but missed out the const.
Or, if you wrote saidMap.insert(std::make_pair(element.PointerToMyObj, str)) then that should have worked and something else is wrong in your code.
But it's much easier to use emplace:
saidMap.emplace(element.PointerToMyObj, str);
This C++11 version of insert has all the magic machinery needed to make that work "transparently".
Your code is almost alright. You're getting this compiler error because map::insert really doesn't have such overload. It's a tiny detail you've missed on reading up when looking at the std::map documentation. It is so that map::insert doesn't work as implicit constructor, which is how you are trying to use it in the pasted code.
This is something you can achieve by emplacing - map::emplace:
for(auto element : myList){
Datastruct str;
str.property1 = element.property1;
str.property2 = element.property2;
saidMap.emplace(element.PointerToMyObj, str);
}
Using map::insert(): The insert function is used to insert the key-value pair in the map and has 3 general overloads, in fact, they are more, but these are the main ideas behind how to insert in a map.
insert(pair): simply inserts a new pair in the map, where pair.first is the key and pair.second is the value. Only happens when the key is not already in the map.
insert(it, pair): insert using an iterator and a pair, where it is a pointer to the location where you want to insert your pair at.
insert(begin, end): used for copying the elements from another map by accepting iterators to begin and end of the map.
In your case, you've missed the to actually pass a pair. You can construct it inside of the insert argument list as follows:
for(auto element : myList){
Datastruct str;
str.property1 = element.property1;
str.property2 = element.property2;
saidMap.insert( /*implicitly derive a pair as:*/ { element.PointerToMyObj, str } );
}
Note: This is a post-C++11 functionality, so make sure you're setting compiler's C++ version to at least that.
I've reproduced your code with the working version of the map::insert in Compiler Explorer (godbolt) for you have a look (in both gcc and clang compilers): https://godbolt.org/z/7Mqut0.
Hope this helps!

Using the Lambda Function with Objects and for_each loops

I'm trying to better understand a few fundamental concepts about working with the lambda functions with a vector of objects and std::for_each() loops.
I'm attempting to pass the const int contents of someObjectVector.end()->someObjectVectorMethod() into i, but just can't find a way to make it happen.
I also want to use those iterators to set the parameters of the std::for_each() loop. Is this just not possible, or am I approaching this the wrong way syntactically?
std::for_each(someObjectVector.begin()->someObjectVectorMethod(), (someObjectVector.end()->getSomeObjectVectorData(), [&](int i)
{
someObjectVector[0].setSomeObjectVectorDate() + i;
});
Your syntax is definitely wrong.
As input, std::for_each() expects
a range of elements denoted by 2 input iterators
a unary function object that each element in that range will be passed to as the sole input parameter.
In your code, someObjectVectorMethod() and getSomeObjectVectorData() are not iterators, and your lambda doesn't accept a vector element as input.
What are you TRYING to accomplish with your code? You probably need something more like this instead:
std::vector<YourObjectType> someObjectVector;
...
std::for_each(someObjectVector.begin(), someObjectVector.end(),
[](YourObjectType &obj) {
obj.setSomeObjectVectorData(...);
}
);
Or:
std::vector<YourObjectType*> someObjectVector;
...
std::for_each(someObjectVector.begin(), someObjectVector.end(),
[](YourObjectType *obj) {
obj->setSomeObjectVectorData(...);
}
);
Depending on how someObjectVector is actually declared in your code.
Tweak the above lambdas to suit your actual needs.

Using array to convert MapResult to an array

I'm having a bit of trouble using array from std.array to convert a MapResult to a specific array type. My problem is as follows:
I have an array a of objects, each of which has a publically-accessible field val. I would like to use map from std.algorithm to go over a and return an array of all the values of the val members. My code looks something like this:
import std.algorithm:map;
import std.array:array;
//import for my object type, which I call Box here
ulong[] fun (Box[] a) {
return array!(ulong[])(map!(function ulong(Box x) {return x.val;})(a);
}
However, when I try to do this, the compiler gives me an error saying that array cannot deduce the function from the argument types !(ulong[])(MapResult!(_funcliteral3,Box[])). Does that mean that MapResults aren't ranges, and is there a way to get what I want?
actually it means that the compiler believed that (ulong[])(MapResult!(_funcliteral3,Box[])) was the template parameter instead of ulong[]
nest your parenthesis properly and it should be fixed
return array!(ulong[])(map!(function ulong(Box x) {return x.val;})(a));

C++ pass STL container items as reference

I have a map of type std::map<std::string, std::vector<MyClass>>. The map is filled in this way that I create a vector and put it with a guid as a pair into the map. Then I want to call a function, give the just inserted vector to it and let it fill the vector. It looks like that:
{
std::string guid = "aGUID"
std::vector<MyClass> vec_myClass(0);
my_map[guid] = vec_myClass;
std::vector<MyClass>& vec_ref = my_map[guid];
FillVector(vec_ref);
}
FillVector(std::vector<MyClass>& vec) { vec.push_back(...); }
I think the [] operator returns a reference of the item in my_map, which I can give to a function to work with it, but my application crashes at this point. I am putting the vector first into the map (when it is empty) because I want to avoid copying effort as function FillVector puts lots of items into the vector. Where is my mistake? Might it be wrong to pass a reference by reference to a function? Or is there a clearly better solution to this? I prefer references over pointers here. Thx, and all the best.
All that code simplifies to:
{
std::string guid = "aGUID"
FillVector(my_map[guid]);
}
Btw. I think your problem does not appear to be here, but in code you don't show us...
std::map operator would create value for the key internally if it does not exist. see this link. passing the reference to function is ok, the problem seem to be somewhere else in your code.

C++,ANTLR and VECTORS

I have an ANTLR rule that would return a vector:
main returns [std::vector<int> v]
:
('ERROR' t3=INT{v.push_back(atoi((const char*)$t3.text->chars));}
'='t4=INT{v.push_back(atoi((const char*)$t4.text->chars));}
);
Then I call it from C++ and try to get the vector data.
However, my problem is that ANTLR3 automatically initialized the vector v to NULL, which isn't allowed and gives me an error.
If I generate the C++ output of antlr and try to compile with my project it gives an error.
I manually went to the parsedfile that ANTLR outputs and removed the setting to NULL option and compiled again and everything worked out.
I can possibly see to solutions to this problem:
1) initializing the vector myself from ANTLR (DONT KNOW HOW TO INITIALIZE VECTORS)
2) Prevent ANTLR from initializing my vector (Not sure if it can be done)
3) Always manually go change the initialization (Not good practice)
4) Find another way to return the vector, tried to return a pointer to array I get the following error:
error: conversion from ‘std::vector<int, std::allocator<int> >*’ to non-scalar type ‘std::vector<int, std::allocator<int> >’ requested
Any help?
I think you want to do something like this:
main returns [std::vector<int> *v]
:
#init { v = new std::vector<int>(); }
( rule content, using *v in actions );
ANTLR can then initialize your return value to NULL, which I think it always does. The #init block creates an empty vector for you to use.
Of course, you will want to actually use a smart pointer like shared_ptr to avoid potential memory leaks as well.
You can initialize vectors this way:
vector<int> a(2,3); //vector a contains 2 elements: 3 and 3
a[0] = 4;//vector a contains 2 elements: 4 and 3
vector<int> b;
b = a;
And there are some other ways you can check here: http://www.cplusplus.com/reference/vector/vector/vector/
EDIT:
If you want to initialize with zeros:
vector<int> a(2);
should do the work, the vector a will contain 2 zeros.