Adding to a vector of pair - c++

I have a vector of pair like such:
vector<pair<string,double>> revenue;
I want to add a string and a double from a map like this:
revenue[i].first = "string";
revenue[i].second = map[i].second;
But since revenue isn't initialized, it comes up with an out of bounds error. So I tried using vector::push_back like this:
revenue.push_back("string",map[i].second);
But that says cannot take two arguments. So how can I add to this vector of pair?

Use std::make_pair:
revenue.push_back(std::make_pair("string",map[i].second));

IMHO, a very nice solution is to use c++11 emplace_back function:
revenue.emplace_back("string", map[i].second);
It just creates a new element in place.

revenue.pushback("string",map[i].second);
But that says cannot take two arguments. So how can I add to this vector pair?
You're on the right path, but think about it; what does your vector hold? It certainly doesn't hold a string and an int in one position, it holds a Pair. So...
revenue.push_back( std::make_pair( "string", map[i].second ) );

Or you can use initialize list:
revenue.push_back({"string", map[i].second});

Read the following documentation:
http://cplusplus.com/reference/std/utility/make_pair/
or
http://en.cppreference.com/w/cpp/utility/pair/make_pair
I think that will help. Those sites are good resources for C++, though the latter seems to be the preferred reference these days.

revenue.push_back(pair<string,double> ("String",map[i].second));
this will work.

You can use std::make_pair
revenue.push_back(std::make_pair("string",map[i].second));

Try using another temporary pair:
pair<string,double> temp;
vector<pair<string,double>> revenue;
// Inside the loop
temp.first = "string";
temp.second = map[i].second;
revenue.push_back(temp);

Using emplace_back function is way better than any other method since it creates an object in-place of type T where vector<T>, whereas push_back expects an actual value from you.
vector<pair<string,double>> revenue;
// make_pair function constructs a pair objects which is expected by push_back
revenue.push_back(make_pair("cash", 12.32));
// emplace_back passes the arguments to the constructor
// function and gets the constructed object to the referenced space
revenue.emplace_back("cash", 12.32);

As many people suggested, you could use std::make_pair.
But I would like to point out another method of doing the same:
revenue.push_back({"string",map[i].second});
push_back() accepts a single parameter, so you could use "{}" to achieve this!

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!

C++11 std::array slice

I have a matrix like this:
array<array<double, DISMAX>, DISMAX> Md;
and a vector like this:
array<double, DISMAX> matrixLine;
DISMAX is a constant.
My question: How can I copy that vector to one line of the matrix without using a for loop? Is it possible?
The simplest method is to do the obvious:
Md[0] = matrixLine;
There is still a loop but the std::array hides the details.
Copy assignment, e.g., Md[0] = matrixLine, should work just fine.

Transform data from vector to other with no default constructor

I used to use this way to copy data with some changes from container to container:
std::vector<Tsrc> source{Tsrc(),Tsrc(2),Tsrc(3),Tsrc(4)};
std::vector<Tdst> dst(source.size());
std::transform(begin(source),end(source),begin(dst),[](Tsrc& item){
return do_something(item);
}
First of all, is the previous code standard and clean? any enhancing may be applied?
Secondly, I now want to do the same but for a Tdst that does not have a default constructor. So, the above code will not work. I replaced it with:
std::vector<Tsrc> source{Tsrc(),Tsrc(2),Tsrc(3),Tsrc(4)};
std::vector<Tdst> dst;
dst.reserve(source.size());
for(auto& item:dst){
dst.emplace_back(do_something(item));
}
Is it the right way to do it? any advice?
What you are doing looks fine. You can avoid the explicit loop by using std::back_inserter. Also, since the elements of the original range aren't being modified the lambda's parameter should be made const:
dst.reserve(source.size());
std::transform(begin(source), end(source), back_inserter(dst),
[](const Tsrc& item){return do_something(item);});

How do you create an array of member function pointers with arguments?

I am trying to create a jump table for a fuzzy controller. Basically, I have a lot of functions that take in a string and return a float, and I want to be able to do something along the lines:
float Defuzzify(std::string varName, DefuzzificationMethod defuzz)
{
return functions[defuzz](varName);
}
where DefuzzificationMethod is an enum. The objective is to avoid a switch statement and have a O(1) operation.
What I have right now is:
float CenterOfGravity(std::string varName);
std::vector<std::function<float (std::string)>> defuzzifiers;
Then I try to initialize it in the constructor with:
defuzzifiers.reserve(NUMBER_OF_DEFUZZIFICATION_METHODS);
defuzzifiers[DEFUZZ_COG] = std::bind(&CenterOfGravity, std::placeholders::_1);
This is making the compiler throw about 100 errors about enable_if (which I don't use anywhere, so I assume std does). Is there a way to make this compile ? Moreover, is there a way to make this a static vector, since every fuzzy controller will essentially have the same vector ?
Thanks in advance
Reserve just makes sure there's enough capacity, it doesn't actually mak the vector's size big enough. What you want to do is:
// construct a vector of the correct size
std::vector<std::function<float (std::string)>> defuzzifiers(NUMBER_OF_DEFUZZIFICATION_METHODS);
// now assign into it...
// if CentorOfGravity is a free function, just simple = works
defuzzifiers[DEFUZZ_COG] = CenterOfGravity;
// if it's a method
defuzzifiers[DEFUZZ_COG] = std::bind(&ThisType::CenterOfGravity, this, std::placeholders::_1);
Now this might leave you some holes which don't actually have a function defined, so maybe you want to provide a default function of sorts, which the vector constructor allows too
std::vector<std::function<float (std::string)>> defuzzifiers(
NUMBER_OF_DEFUZZIFICATION_METHODS,
[](std::string x) { return 0f; }
);
An unrelated note, you probably want your functions to take strings by const-ref and not by value, as copying strings is expensive.

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.