No Matching function to call. C++ STL - c++

I'm new to C++ STL. I'm writing a function to check whether one vector is an subset of another(Duplicate elements also count) and print 'Yes' or 'No'. I have come up with the following code :
void checkMagazine(vector<string> magazine, vector<string> note) {
vector<string>::iterator a;
for(int i=0;i<note.size();i++)
{
a=find(magazine.begin(),magazine.end(),note[i]);
if(a==magazine.end())
{
printf("No");
return;
}else magazine.erase(a-magazine.begin());
}
printf("Yes");
}
But,I'm getting the following compilation error :
error: no matching function for call to ‘std::vector<std::__cxx11::basic_string<char>
>::erase(__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char>*,
std::vector<std::__cxx11::basic_string<char> > >::difference_type)’
}else magazine.erase(a-magazine.begin());
I'm trying to use erase to delete the found element in magazine.Is there some problem with the type of declaration of the iterator? Why is this happening?
And also if there are alternate methods/logic/inbuilt-functions to get the required job done using STL, Please let me know since I'm new to this and trying to learn it.

erase takes an iterator. You have that iterator, it's called a. But you then convert the iterator a into an offset relative to begin(). erase does not have an overload which takes an offset.
The Standard Library has alternatives if the vectors would be sorted, but we don't see the calling code so we can't assume that.

Related

no match for ‘operator==’ (operand types are ‘hockey::Personne* const’ and ‘const hockey::Personne’)

my function tries to find if an element already exists in a vector of a class objects pointers
I kind of understand the source of the problem but I can't seem to find a solution without having the implement a method for the == operation ,
the method in the cpp file :
bool Annuaire::PersonneEstDejaPresente(const Personne& p_personne) const{
vector<Personne*>::const_iterator iter;
iter = std::find(m_vMembres.begin(), m_vMembres.end(), p_personne);
return true;
//the return here is just for the sake of testing
}
the vector defined in the header file private part :
std::vector<Personne*> m_vMembres;
the error I get from the compiler is in the title,
I would be really apreciate any help.
The problem is that have an vector of pointers but what you are looking for is not a pointer.
This would compile
iter = std::find(m_vMembres.begin(), m_vMembres.end(), &p_personne);
but this will compare pointers not Personne objects. I guess that you really want to compare persons, so you might be better off using std::find_if instead of std::find.
The other thing you should consider is using vector<Personne> instead of vector<Personne*>. Do you have a good reason to use pointers in the first place?

Insert new pair in std::map<CString, CString>

I have two lists and a name to find. If the name to find is not in the first list then it might be in the second list with a slightly different format. Conversion function between the two formats are given.
std::map<CString, CString>* convertedNames;
BOOL CSome::SeekNameWithConversion(std::set<CString> names, CString nameToFind)
{
for (auto it = names.begin(); it != names.end(); ++it)
{
if (nameToFind.Compare(*it) == 0) return true;
auto convertedIt = convertedNames->find(*it);
if (convertedIt != convertedNames->end() &&
nameToFind.Compare(convertedIt->second) == 0)
return true;
CString justConvertedName = ConvertToTheOtherFormat(nameToFind);
convertedNames->insert(*it, justConvertedName); // Error here
return nameToFind.Compare(justConvertedName) == 0;
}
}
The error which appears is:
error C2675: unary '++':
'ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<_CharType>>>' does
not define this operator or a conversion to a type acceptable to the
predefined operator
I would like to know why the operator ++ is involved here and then how should I treat this error.
Most of the various insert functions of std::map require an iterator. Instead, you pass the pointed-to-object, (which is a CString, I suppose):
convertedNames->insert(*it, justConvertedName);
^^^
this is a CString, not a std::map<CString,CString>::iterator
If you want to insert a key-value pair, use the map's value_type instead which is basically a std::pair made up of key and value:
convertedNames->insert(std::make_pair(*it, justConvertedName));
The first argument to map::insert is an iterator, not a CString. Internally, the method is trying to increment the iterator. This apparently makes a call to operator++. You don't need to use this insert overload. It's intended to improve performance when you know a position close to where the element will be inserted. Just call convertedNames->insert(std::make_pair(*it, justConvertedName)) instead.
So the first thing to understand is that templates are always fully implemented in the header, as any classes required are built with that object (just think if the std lib had all possible std::vector implementations built in!)
This means that the implementation of the template is exposed - and in this case, there's a ++ somewhere there. If you take the whole error printed (it'll be quite a few more lines) you may even be told which parameter you've got wrong.
In any case, we can see that *it is clearly going to be a CString, but I'd guess that this
... convert to the other format
is probably not returning what you think

Efficiently remove last element from std::list

This seems like a simple problem, and it is certainly doable, but I'd like to do it efficiently.
The Objective:
Remove the last element from a std::list if it meets a condition.
The Problem:
My compiler (MSVC++ 10) is unhappy about casting a reverse iterator to a const iterator for a method call to std::list.erase(). The message is:
error C2664: 'std::_List_iterator<_Mylist>
std::list<_Ty>::erase(std::_List_const_iterator<_Mylist>)' : cannot
convert parameter 1 from 'std::reverse_iterator<_RanIt>' to
'std::_List_const_iterator<_Mylist>'
The Code I Tried:
std::list<mytype> mylist;
// lots of code omitted for clarity
bool ends_badly = true;
while(ends_badly && mylist.size() > 0)
{
auto pos = mylist.crbegin(); // Last element in the list
if ((*pos)->Type() == unwanted)
{
mylist.erase(pos); // Here is where the compiler complains
}
else
{
ends_badly = false;
}
}
I can get around this by using forward iterators and looping through the list to the end, but that's so cumbersome. The compiler is OK with a forward iterator in this context, and I tried casting a the reverse iterator to a const iterator but the compiler didn't like that either.
Erasing a list element from a bidirectional list using a reverse iterator seems like a reasonable thing. Is there something obvious I'm missing here?
I suppose that you can simplify your code snippet doing it the next way:
while (!mylist.empty() && mylist.back()->Type() == unwanted) {
mylist.pop_back();
}
To fix the specific error in your code Can I convert a reverse iterator to a forward iterator?
mylist.erase((pos+1).base());
Using std::reverse_iterator::base
The base iterator refers to the element that is next (from the std::reverse_iterator::iterator_type perspective) to the element the reverse_iterator is currently pointing to.
Anyway, pop_back is the best choice in your case.

Delete elements in vector by position?

In my class I am trying to remove an element from a std::vector using a for loop. However, when I try to remove the element, I receive an error and I am not quite sure how to solve it. The error I get is:
Error 4 error C2679: binary '+' : no operator found which takes a right-hand operand of type 'Enemy *' (or there is no acceptable conversion)
void Enemy::UpdateEnemies(SDL_Renderer * render)
{
for (int i = enemies.size() - 1; i >= 0; i--)
{
enemies[i]->Update();
if (enemies[i]->Active == false)
{
// Receive the error here
enemies.erase(enemies.begin() + enemies.at(i));
}
}
if ((SDL_GetTicks()-prevSpawnTime)/1000.0f > enemySpawnTime)
{
prevSpawnTime = SDL_GetTicks();
//Add an anemy
AddEnemy(render);
}
}
Other answers have given you the naive solution. However, if you have more than one enemy to remove, you need a better solution.
Using std::remove_if from <algorithm> would be better in this case. That will avoid repeated shuffling of the items in your vector. It works by moving all the ones you want to remove to the end of the container, and then giving you an iterator to the beginning of those.
auto removed_iter = std::remove_if( enemies.begin(), enemies.end(),
[]( const Enemy * e ) { return e->IsActive(); } );
enemies.erase( removed_iter, enemies.end() );
In this case you would have to update all your enemies first. If that doesn't need to be done in reverse order, then:
for( auto e : enemies ) e->Update();
Assuming that you want to remove the i-th element, you need to do
enemies.erase(enemies.begin() + i);
or better
enemies.erase(std::next(enemies.begin(), i));
In your case enemies.at(i) returns the dereferenced iterator at position i, i.e. an element of type Enemy, and not i or the iterator for position i.
A better way is to use reverse iterators:
for(auto it = enemies.rbegin(); it != enemies.rend(); ++it)
{
(*it)->Update();
if ((*it)->Active == false)
{ // need `base()` to convert to regular iterator, then substract 1
enemies.erase(std::prev(it.base())); // remove the current position
/* or, equivalently
enemies.erase(std::next(it).base());
*/
}
}
This line:
enemies.erase(enemies.begin() + enemies.at(i));
enemise.at(i) returns the Enemy that is stored in the vector.
enemies.begin() is a pointer
As the error says, you are trying to add pointer and vector.
You probably want just to call:
enemies.erase(enemies.begin() + i);
In addition to what others have said, I would take it a step further and suggest that erasing from a vector within a loop could cause undefined behavior. I don't see a break, so I assume that there could be multiple inactive enemies. Instead of writing your own loop, consider using the std::remove_if algorithm. Essentially your code is an attempt to add an iterator with an object reference which will fail to compile. The remove_if solution will essentially copy all enemies where Active==false to the end of the container while shifting everything else forward. It provides a convenient way to first identify the things to remove, and then erase them all at once. Additionally if you don't have a C++11 compiler the same thing will work if you use a different kind of predicate. The remove_if link contains an example of a function, but you can also use a functor.
enemies.erase(std::remove_if(enemies.begin(), enemies.end(), [](const Enemy* e){ return e->Active == false; }), enemies.end());
For more information check these out.
What is a lambda expression in C++11?
http://www.cplusplus.com/reference/algorithm/remove_if/
C++ Functors - and their uses

c++ stl iterators

I am getting a lot of errors trying to use an iterator for three dimensional vector of sets of ints. See the following code (which is just select pieces, because the whole thing is too long; I think this should be enough to see what is wrong, but let me know if it isn't):
vector<vector<vector<set<int> > > > particles_celllist;
vector<vector<vector<set<int> > > >::iterator cell_iter;
map<int,map<int,Particle> > particle_grid;
for (cell_iter=particles_celllist[wx][wy][wz].begin();cell_iter!=particles_celllist[wx][wy][wz].end();cell_iter++)
{
double distance_to_cell=sqrt(pow(particles[*cell_iter].position().y()-(wy)*ygridlength,2)+
pow(particles[*cell_iter].position().z()-(wz)*zgridlength,2));
if (distance_to_cell<input_data.diam_large())
{
particle_grid[box_counter][*cell_iter]=particles[*cell_iter];
}
}
Note: wx, wy, wz, and box_counter are ints, ygridlength and zgridlength are doubles, and Particle::position::y (or ::z) and input_data::diam_large return doubles.
I get a multitude of errors:
no match for operator "=" in
"cell_iter=particles_celllist[wx][wy][wz].begin()"
no match for operator "!=" in
"cell_iter!=particles_celllist[wx][wy][wz].end()"
no match for operator "[]" whenever I used [*cell_iter] to call
something
I get the feeling like the error somehow stems from the iterator itself, but I haven't been able to figure it out.
You want set<int>::iterator cell_iter;. Just look again carefully at whose begin() function you're calling.
In C++11 you would of course just have said
auto cell_iter = particles_celllist[wx][wy][wz].begin()
and never noticed that this is hard :-)
particles_celllist[wx][wy][wz] is of type set<int>, so particles_celllist[wx][wy][wz].begin() is of type set<int>::iterator