I am trying to copy a vector of pair to another:
vector<pair<int,int>> vp = {pair<int,int>(1,1), pair<int,int>(2,2)};
vector<pair<int,int>> vp2;
for_each(vp.begin(), vp.end(), [vp2](pair<int,int> p){
if(/*some condition*/){
vp2.push_back(p);
}
});
I get this compiler error:
error: passing ‘const std::vector<std::pair<int, int> >’ as ‘this’ argument of ‘void std::vector<_Tp, _Alloc>::push_back(value_type&&) [with _Tp = std::pair<int, int>, _Alloc = std::allocator<std::pair<int, int> >, value_type = std::pair<int, int>]’ discards qualifiers
Using gcc 4.5.1 on ubuntu.
As an alternative to Konrad's answer; if the goal is simply to copy the elements of the first vector if they match a certain condition, would std::copy_if not be a better match?
vector<pair<int,int>> vp = {pair<int,int>(1,1), pair<int,int>(2,2)};
vector<pair<int,int>> vp2;
copy_if(vp.begin(), vp.end(), back_inserter(vp2), [](pair<int,int> p) { return /* some condition */; });
Copying is much easier than that:
vector<pair<int,int>> vp2(vp.begin(), vp.end());
or even:
vector<pair<int,int>> vp2 = vp; // or
vector<pair<int,int>> vp2(vp);
The error in your code is that you capture vp2 by value which effectively makes it const in your anonymous method, and you cannot call push_back on a const vector. The following should work:
for_each(vp.begin(), vp.end(), [&vp2](pair<int,int> p){vp2.push_back(p);});
But there’s no reason to use this instead of the simpler code.
Related
I have a vector of a map of int and float
std::vector<std::map<int, float>> datad;
And I want to iterate over the maps in vector and inside over pairs in map
for (std::vector<std::map<int, float>>::iterator currentMap = datad.begin(); currentMap < datad.end(); ++currentMap)
{
for (std::map<int, float>::iterator it = currentMap->begin(); it < currentMap->end(); ++it)
{/*some code here*/}
}
But in the second loop g++ compiler gives an error:
no match for ‘operator<’ (operand types are ‘std::_Rb_tree_iterator<std::pair<const int, float> >’ and ‘std::map<int, float>::iterator’ {aka ‘std::_Rb_tree_iterator<std::pair<const int, float> >’})
But isn't it looks like the types
std::_Rb_tree_iterator<std::pair<const int, float>>
std::_Rb_tree_iterator<std::pair<const int, float>>
are the same?
Yes, I see that compiler says the currentMap->end() have the type std::map<int, float>::iterator but...it is aka _Rb_tree_iterator...
maybe
static_cast<std::_Rb_tree_iterator<std::pair<const int, float>>>(currentMap->end())
What is the easiest way to continue using iterators and fix the problem?
PS. static_cast don't work, it gives
no match for ‘operator<’ (operand types are ‘std::map<int, float>::iterator’ {aka ‘std::_Rb_tree_iterator<std::pair<const int, float> >’} and ‘std::map<int, float>::iterator’ {aka ‘std::_Rb_tree_iterator<std::pair<const int, float> >’})
PSS. I've also tried auto but it also doesn't work (the same error as the first one)
std::map's iterators are bidirectional iterators, not random access iterators. Therefore they do not provide relational comparison operators. You can only equality-compare them.
So replace < with !=, which is the standard way of writing iterator loops. Or even better, replace the loop with a range-for loop:
for (auto& currentMap : datad)
{
for (auto& el : currentMap)
{
/* Use el here as reference to the (pair) element of the map. */
}
}
I am trying to implement the solution to the problem found at Link.
Here is my snippet of code
bool compareVec(vector<int> a, vector<int> b) {
return std::equal(a.begin(), a.end(), b.begin());
}
vector<vector<int> > ans;
ans.erase(std::remove_if(ans.begin(), ans.end(), compareVec), ans.end());
I am getting the following errors
/usr/include/c++/4.8/bits/stl_algo.h: In instantiation of
'_RandomAccessIterator std::__find_if(_RandomAccessIterator,
_RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [with
_RandomAccessIterator = __gnu_cxx::__normal_iterator<std::vector<int>*,
std::vector<std::vector<int> > >; _Predicate = bool (*)(std::vector<int>,
std::vector<int>)]':
/usr/include/c++/4.8/bits/stl_algo.h:4465:41: required from '_IIter
std::find_if(_IIter, _IIter, _Predicate) [with _IIter =
__gnu_cxx::__normal_iterator<std::vector<int>*, std::vector<std::vector<int>
> >; _Predicate = bool (*)(std::vector<int>, std::vector<int>)]'
/usr/include/c++/4.8/bits/stl_algo.h:1144:64: required from '_FIter
std::remove_if(_FIter, _FIter, _Predicate) [with _FIter =
__gnu_cxx::__normal_iterator<std::vector<int>*, std::vector<std::vector<int>
> >; _Predicate = bool (*)(std::vector<int>, std::vector<int>)]'
solution.cpp:40:64: required from here
/usr/include/c++/4.8/bits/stl_algo.h:214:23: error: too few arguments to
function
if (__pred(*__first))
^
/usr/include/c++/4.8/bits/stl_algo.h:218:23: error: too few arguments to
function
if (__pred(*__first))
^
/usr/include/c++/4.8/bits/stl_algo.h:222:23: error: too few arguments to
function
if (__pred(*__first))
^
Can anyone help me out in debugging this?
Thanks in advance
EDIT
The elements of vector are sorted and all these vectors are also sorted.
Unique also gives an error. I am unable to figure out why?
Why is the example given in the link I provided, not helpful here?
std::remove_if requires a unary predicate. You pass a binary predicate, which causes your errors (/usr/include/c++/4.8/bits/stl_algo.h:222:23: error: too few arguments to function → your function takes two arguments, not one).
Further, std::remove_if does its removals with no consideration of other elements (which is why it accepts a unary predicate), so it isn't actually what you're looking for.
What you want to use is std::unique, which does require the compareVec you've implemented. However, std::vector already provides the operator== overload, so that implementation is actually redundant! Also, you say that you get an error when using std::unique. Try passing your parameters as const&.
Thus, when your outer vector and inner vectors are already sorted, the solution is as it'd be for any other vector of sorted elements:
outer.erase(std::unique(outer.begin(), outer.end()), outer.end());
Okay, since this is not marked with C++11, I will use a functor instead of a lambda.
The first problem you have is that remove_if takes a UnaryPredicate, which means it should only accept a single argument.
The second issue is also related to your understanding of remove_if. After you fix compareVec to only accept one argument, you're left wondering how you could possibly compare all elements against each other.
You could approach this one of two ways:
Sort your vector of vectors (< operator is defined lexicographically for vector) and then use std::unique (Examples) (More examples).
In the link you provided (same as the one I just linked to), notice that they sort first, and you do not.
Or, if there's no clear definition of < for your elements, only ==, you could perform an O(N2) lookup/erase on each subsequent item (shown below):
Comparison functor (could make as a lambda in C++11 and greater)
struct CompareVec
{
CompareVec(const std::vector<int>& _in) : compare_against(_in){}
bool operator()(const std::vector<int>& rhs) const
{
return compare_against == rhs;
};
const std::vector<int>& compare_against;
};
To be used like so:
for (size_t i = 0; i < ans.size(); ++i)
{
CompareVec comparator(ans[i]);
ans.erase(std::remove_if(ans.begin()+i+1, ans.end(), comparator), ans.end());
}
Live Demo (Compiled in C++11 for want of initializing test vectors with initializer lists)
Edit
In C++11 we can get rid of the CompareVec functor and replace it with a lambda:
for (size_t i = 0; i < ans.size(); ++i)
{
ans.erase(std::remove_if(ans.begin()+i+1, ans.end(),
[&ans, &i](const std::vector<int>& _rhs)
{
return ans[i] == _rhs;
}) , ans.end());
}
Demo2
I have a specific list with vectors. i want to add a value to a vector. How can I do this?
Here is my code:
//creating the list with vectors
std::list< vector<string> > adjacencylist;
//adding some vectors to the list...
adjacencylist.push_back(std::vector<std::string>(1, "String"));
adjacencylist.push_back(std::vector<std::string>(1, "String"));
adjacencylist.push_back(std::vector<std::string>(1, "String"));
Now I want to add values to the vectors in the list...
I tried for this:
std::list< vector<string> >::const_iterator it = adjacencylist.begin();
(*it).push_back("Some more String");
I thought that this would work. So I could iterate over all vectors and insert the values that I want. But it does not work. Here the output of the compiler:
example.cpp: In function ‘int main(int, char**)’:
example.cpp:148:31: error: passing ‘const std::vector<std::basic_string<char> >’ as ‘this’ argument of ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::basic_string<char>; _Alloc = std::allocator<std::basic_string<char> >; std::vector<_Tp, _Alloc>::value_type = std::basic_string<char>]’ discards qualifiers [-fpermissive]
(*it).push_back("test");
Because you have declared it as a const_iterator you have made it such that what it references cannot be edited. When you call push_back you are attempting to edit the vector that it points to. You need to replace:
std::list< vector<string> >::const_iterator it = adjacencylist.begin();
(*it).push_back("Some more String");
with
std::list< vector<string> >::iterator it = adjacencylist.begin();
(*it).push_back("Some more String");
Read up on general constness here and there is more specific information on const_iterator here.
Use simply an iterator. Also you can use it -> push_back instead of (*it).push_back.
This is an example:
for (list< vector<string> > it = adjacencylist.begin(); it != adjacencylist.end(); ++it)
{
it -> push_back("Your std::string");
}
I have an STL map that I want to iterate through, and can't seem to get the code to work. The code is:
//PowerupInfo is a struct defined in this class's header file
std::map<std::string, PowerupInfo> powerups;
...populate powerups
std::map<std::string, PowerupInfo>::iterator iter;
for (iter = powerups.begin(); iter != powerups.end(); iter++) {
return iter->second.type ;
}
The error message I get is:
error: no match for 'operator=' in 'iter = (((const std::map<std::string, PowerupInfo, std::less<std::string>, std::allocator<std::pair<const std::string, PowerupInfo> > >)((const PowerupList)this)) + 24u)->std::map<_Key, _Tp, _Compare, _Alloc>::begin with _Key = std::string, _Tp = PowerupInfo, _Compare = std::less<std::string>, _Alloc = std::allocator<std::pair<const std::string, PowerupInfo> >'|
note: candidates are: std::_Rb_tree_iterator<std::pair<const std::string, PowerupInfo> >& std::_Rb_tree_iterator<std::pair<const std::string, PowerupInfo> >::operator=(const std::_Rb_tree_iterator<std::pair<const std::string, PowerupInfo> >&)|
So I would normally assume that the problem has to do with setting iter equal to something it doesn't like, as it's not finding a match for 'operator='. But why? Why wouldn't that assignment work?
EDIT:
Turns out the method WAS const, causing the reference to powerups to be const as well, causing the error. I was just doing a bad job reading my own code. Thanks guys!
Your map name is poweruplist not powerups (You are using this name in the for loop). If this is not the cause of the error, then it looks like you are for loop is in a function which accepts the map by const reference (or is a const member function of a class). In that case your type of iterator should be const_iterator and not iterator.
Reformatting error code to make it readable:
error: no match for 'operator=' in
'iter =
((
(const std::map<std::string, PowerupInfo>*)((const PowerupList*)this)
)
+ 24u
)->std::map<std::string, PowerupInfo>::begin()'
Does not look the error message to the code you supplied.
Please cut and past the code. Otherwise it is meaningless.
Consider this program:
#include <map>
#include <vector>
typedef std::vector<int> IntVector;
typedef std::map<IntVector,double> Map;
void foo(Map& m,const IntVector& v)
{
Map::iterator i = m.find(v);
i->first.push_back(10);
};
int main()
{
Map m;
IntVector v(10,10);
foo(m,v);
return 0;
}
Using g++ 4.4.0, I get his compilation error:
test.cpp: In function 'void foo(Map&, const IntVector&)':
test.cpp:8: error: passing 'const std::vector<int, std::allocator<int> >' as 'this' argument of 'void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = int, _Alloc = std::allocator<int>]' discards qualifiers
I would expect this error if I was using Map::const_iterator inside foo but not using a non-const iterator.
What am I missing, why do I get this error?
The keys in a map are constant. A map is a tree, and you can't just going around changing the keys or you'll break its invariants. The value_type of a map with Key and Value is std::pair<const Key, Value>, to enforce this.
Your design needs some changing. If you really need to modify the key, you need to remove the element, change its key, and re-insert it with the new key.
Also concerning your example specifically, you will get undefined behavior (if this did work). Your map is empty when you call foo, so the iterator returned by find will be m.end(); the element doesn't exist. But then you'd go on to modify this non-existent element: ka-boom. Whenever you find something, you should check that it was found before you attempt to use it.