TGuildMemberContainer::iterator it;
if ((it = m_member.find (p->dwPID)) == m_member.end())
{
m_member.insert (std::make_pair (p->dwPID, TGuildMember (p->dwPID, p->bGrade, p->isGeneral, p->bJob, p->bLevel, p->dwOffer, p->szName)));
}
else
{
TGuildMember& r_gm = it->second;
r_gm.pid = p->dwPID;
r_gm.grade = p->bGrade;
r_gm.job = p->bJob;
r_gm.offer_exp = p->dwOffer;
r_gm.is_general = p->isGeneral;
}
Hi, i want to apply auto transform intro my codes, but i'm stuck.
If i add auto
if (auto it = m_member.find (p->dwPID) == m_member.end())
The auto assign a bool
if ( bool it = m_member.find (p->dwPID) == m_member.end())
This say Visual Studio intelisense.
My question, why auto assign me a bool and not the corect iteration range ?
Because the compiler is parsing it as:
if (auto it = (m_member.find (p->dwPID) == m_member.end()))
which is a boolean expression. You can't write it as:
if ((auto it = m_member.find (p->dwPID)) == m_member.end())
because putting the variable declaration inside brackets like that is not allowed.
I find creating variables in if hard to read. Just use:
const auto it = m_member.find(p->dwPID);
if (it == m_member.end())
...
In C++17, this can be done as
if (auto it = m_member.find (p->dwPID); it == m_member.end())
which avoids the scope problem mentioned in the other answer.
Related
In following peace of code, I'm trying to find another object that has the same coordinates as this. How to do it correctly?
auto& organism_vector = world->get_vector();
auto attacked_organism = find_if(begin(organism_vector), end(organism_vector), [this](const unique_ptr<Organism>& attacked_organism)
{
return this->get_coordinates() == attacked_organism->get_coordinates() && *this != *attacked_organism;
});
Another thing, when I finally manage to get this iterator, how to refer to attacked_organism class methods?
*attacked_organism.get_coordinates();
Change *this != *attacked_organism to this != attacked_organism.get():
auto& organism_vector = world->get_vector();
auto attacked_organism = find_if(begin(organism_vector), end(organism_vector),
[this](const unique_ptr<Organism>& attacked_organism)
{
return this->get_coordinates() == attacked_organism->get_coordinates() && this != attacked_organism.get();
}
);
Once you have the iterator that find_if() returns (and after you validate that it is not the end iterator), you can call methods on the Organism by first dereferencing the iterator to access the unique_ptr that is holding the Organism* pointer, and then dereferencing the unique_ptr to access the Organism itself:
auto attacked_organism = find_if(...);
if (attacked_organism != end(organism_vector))
{
(**attacked_organism).get_coordinates();
or:
(*attacked_organism)->get_coordinates();
...
}
On a side note: I would not recommend giving your iterator variable the same name as the lambda parameter. That just makes things confusing to read. The lambda is trying to find an Organism to attack, but it hasn't actually been attacked yet, so you should name the lambda parameter more appropriately, eg:
auto attacked_organism = find_if(begin(organism_vector), end(organism_vector),
[this](const unique_ptr<Organism>& candidate_organism)
{
return this->get_coordinates() == candidate_organism->get_coordinates() && this != candidate_organism.get();
}
);
For that matter, I wouldn't really suggest naming the iterator as attacked_organism, either. It is not the actual Organism, it is an iterator to the Organism, so something more like this would be more readable:
auto& organism_vector = world->get_vector();
auto found_iterator = find_if(begin(organism_vector), end(organism_vector),
[this](const unique_ptr<Organism>& candidate_organism)
{
return this->get_coordinates() == candidate_organism->get_coordinates() && this != candidate_organism.get();
}
);
if (found_iterator != end(organism_vector))
{
auto &attacked_organism = *found_iterator;
attacked_organism->get_coordinates();
...
}
I have two lists which contain a bunch of elements of the same type:
std::list<Part> allParts = step.getSubParts();
std::list<Part> toRemove;
for (Part part : allParts)
{
for (Part partTwo : allParts) {
if (part.getEdges() == partTwo.getEdges())
if (part.getFaces() == partTwo.getFaces())
if (part.getShells() == partTwo.getShells())
if (part.getVertices() == partTwo.getVertices())
if (part.getWires() == partTwo.getWires())
{
part.addAmount(1);
toRemove.push_back(partTwo);
}
}
}
I have tried iterating through both and remove from the one but I'm constantly getting the list iterators are incompatible error. This is my latest attempt:
std::list<Part>::iterator it;
for (it = step.getSubParts().begin(); it != step.getSubParts().end();)
{
std::list<Part>::iterator i;
for (i = toRemove.begin(); i != toRemove.end();)
{
if (it->getEdges() == i->getEdges())
if (it->getFaces() == i->getFaces())
if (it->getShells() == i->getShells())
if (it->getVertices() == i->getVertices())
if (it->getWires() == i->getWires())
{
it = step.getSubParts().erase(it);
}
else
{
it++;
}
i++;
}
}
Everything I have tried doesn't work. What is the correct way to do this?
You should consider remove_if or erase_if rather than doing your own erase with the hazard of making iterator invalid within a loop.
By the way, you should write predicate like:
if (it->getEdges() == i->getEdges() &&
it->getFaces() == i->getFaces() &&
it->getShells() == i->getShells() &&
it->getVertices() == i->getVertices() &&
it->getWires() == i->getWires()) {
// do something
}
Your code makes people difficult to understand your purpose(at least me).
erase and erase_if
First of all, it would be a good idea to follow the Don't Repeat Yourself principle and write a comparison function for future use:
auto compare_parts = [](const Part& p1, const Part& p2) -> bool {
return ( (p1.getEdges() == p2.getEdges())
and (p1.getFaces() == p2.getFaces())
and (p1.getShells() == p2.getShells())
and (p1.getVertices() == p2.getVertices())
and (p1.getWires() == p2.getWires()) );
}
You would rewrite the first cycle using it and see how much more simple it looks.
Then why not use c++ built-in methods to erase the elements from the list using the function we wrote? This uses new feature in c++ called binding parameters that would aid us here
#include <functional>
using namespace std::placeholders;
for (auto&& badPart : toRemove) {
auto isBad = std::bind(compare_parts, badPart, _1);
step.getSubParts().remove_if(isBad);
}
And that's how you remove special entries from the list.
I think the cleanest way would be:
1. Implement equality operator for the class Part
You can either put it inside or outside the class, it would look like this if you implement it as an external function
inline bool operator==(const Part& lhs, const Part& rhs) {
return lhs.getEdges() == rhs.getEdges() &&
lhs.getFaces() == rhs.getFaces() &&
lhs.getShells() == rhs.getShells() &&
lhs.getVertices() == rhs.getVertices() &&
lhs.getWires() == rhs.getWires();
}
2. Implement the loop, I would recommend using iterators
This is just one way of doing it
if (allParts.size() > 1) {
for(auto partIt = std::begin(allParts); partIt != std::end(allParts); partIt++) {
for(auto partIt2 = std::next(partIt); partIt2 != std::end(allParts);) { // Manual increasing because we erase stuff
if(*partIt == *partIt2) { // Previously implemented equility operator
partIt->AddAmount(1);
partIt2 = allParts.erase(partIt2); // If erase, use the returned iterator as your next `Part`
} else {
partIt2++; // Only increment if nothing was erased (when you erase iterators get invalidated)
}
}
}
}
So I have a vector of objects
vector<Module*> moduleVector;
and I need to iterate through it and compare an attribute from the object to another attribute I'm pulling from a text file
I'm using an ifstream and getLine() to store the element that needs to be compared to the object's attribute (fileD is the opened file, markModId is the string variable)
getline(fileD, markModId, ' ');
But I am unsure of how I can refer to the object's attributes in an iterator. So my question is,
how do I compare the attribute from the file to the object using an iterator?
For reference here is my object constructor (id is the attribute I want to compare)
Module::Module(string id, string title, string lecturer, int
courseworkWeight)
{
code = id;
name = title;
lect = lecturer;
cwWeight = courseworkWeight;
exMark = 0; //ex mark initialised as 0
/*
Map to store coursework marks
*/
map<string, float> CWmarks;
//cwMarks.clear(); //cw marks map cleared
//create a map that stores
}
And exMark is the attribute that needs to be added to the object. All attributes in the Module constructor are private.
How do I compare the attribute from the file to the object using an
iterator?
Short answer: Suppose you have an iterator std::vector<Module*>::iterator iter you can access the public members of Module class like:
(*iter)->/*public member*/;
Long answer: First of all, you need a getter for private member id and one setter for exMark, by which you can get the id of each Module and compare to the id from the file and then set its exMark to some value.
std::string getId()const { return code; }
void setExMark(const double newMark) { exMark = newMark; }
If you want to change the first true instance of Module, you can use std::find_if for finding the Module:
std::string idFromFile = "two";
auto Condition = [&idFromFile](Module* element){ return element->getId() == idFromFile; };
auto iter = std::find_if(moduleVector.begin(), moduleVector.end(), Condition);
if(iter != moduleVector.end())
(*iter)->setExMark(10.0); // see this
// ^^^^^^^^^
See a sample code here
For multiple instances you can do:
for(auto iter = moduleVector.begin(); iter != moduleVector.end(); ++iter)
if ( (*iter)->getId() == idFromFile)
(*iter)->setExMark(10.0);
Note: In modern C++ you can use smart pointers, instead of raw pointers, which will delete the objects automatically as it goes out of scope.
Simply dereference the iterator to access its Module* pointer, then you can access the object using operator-> however you want, eg:
for (std::vector<Module*>::iterator iter = moduleVector.begin(), end = moduleVector.end(); iter != end; ++iter)
{
Module *m = *iter;
if (m->code == markModId)
m->exMark = ...;
}
Or, if you are using C++11 or later, let the compiler handle the iterator for you:
for (Module *m : moduleVector)
{
if (m->code == markModId)
m->exMark = ...;
}
Or, use a lambda with one of the standard iteration algorithms, eg:
std::for_each(moduleVector.begin(), moduleVector.end(),
[&](Module *m)
{
if (m->code == markModId)
m->exMark = ...;
}
);
If you are only interested in updating 1 Module, then break the loop when the the desired Module is found:
for (std::vector<Module*>::iterator iter = moduleVector.begin(), end = moduleVector.end(); iter != end; ++iter)
{
Module *m = *iter;
if (m->code == markModId)
{
m->exMark = ...;
break; // <-- add this
}
}
for (Module *m : moduleVector)
{
if (m->code == markModId)
{
m->exMark = ...;
break; // <-- add this
}
}
auto iter = std::find_if(moduleVector.begin(), moduleVector.end(),
[&](Module *m) { return (m->code == markModId); });
if (iter != moduleVector.end())
{
Module *m = *iter;
m->exMark = ...;
}
For example I have an vector of objects and they all have attribute PointX so I want to check if all of them have the same value of PointX and if they have it should return true or false whatever.
So in a kind of pseudo-code:
IF ( Object[1].getPointX() == Object[2].getPoint(x) == Object[3].getPoint(x) ){
return true;
}
The problem is that I have more than 55 objects so there has to be a way to compare them without writting them all individually. I know there must be with a for loop but still I have no idea.
thanks in advance.
edit:
#awesomeyi your suggestion seems the easiest and more adequate to my needs (I'm not saying the others are not but I think they are too complicated for a newb like me) but it's not working, even if Xpoints are all the same or different it always returns false. here's what i have:
bool allKilled(){
auto checkpointx = Invader[0].getIfActive();
for(int i = 0; i < 55; ++i){
if(Invader[i].getIfActive() != checkpointx){
return false;}
}
}
the getIfActive() just returns if its true or false, and i want this method to return true if all Active (attribute of the object) of all objects are all false.
Something like this:
auto refx = Object[0].getPointX();
bool b = std::all_of(Object.begin(),
Object.end(),
[refx](TheTypeOfTHeElements& e)
{ return e.getPointX() == ref; });
Obviously you need to check that Objects is not empty.
For loop?
auto checkpointx = Object[0].getPointX();
for(int i = 1; i < Object.size(); ++i){
if(Object[i].getPointX() != checkpointx)
return false;
}
I'd do it something like this:
template<typename Objects, typename Comparison>
bool is_all_same( Objects&& objects, Comparison&& comp ) {
using std::begin; using std::end;
auto&& b = begin(objects);
auto&& e = end(objects);
if (b == e)
return true;
auto&& first = *b;
for( auto&& cur = std::next(first); cur != e; ++cur ) {
if (!comp( first, cur ))
return false;
}
return true;
}
use:
bool all_same_x = is_all_same( objs, []( Obj const& left, Obj const& right )->bool {
return left.getPointX() == right.getPointX();
});
where objs is some container or range containing objects of type Obj.
The above code should work on all standard containers, C style arrays, custom containers that support the new for loops, and is close to optimal performance wise.
In the following code, I try to replace operand(s) of an LLVM instructions. However it doesn't work and nothing is changed. Any idea how to solve this?
for (OI = insn->op_begin(), OE = insn->op_end(); OI != OE; ++OI)
{
Value *val = *OI;
iter = mapClonedAndOrg.find( val );
if( iter != mapClonedAndOrg.end( ) )
{
// Here I try to replace the operand, to no effect!
val = (Value*)iter->second.PN;
}
}
You should use the iterator OI to replace it, instead of the local pointer val. So it should be like this.
for (OI = insn->op_begin(), OE = insn->op_end(); OI != OE; ++OI)
{
Value *val = *OI;
iter = mapClonedAndOrg.find( val );
if( iter != mapClonedAndOrg.end( ) )
{
*OI = (Value*)iter->second.PN;
}
}
What you are doing is simply making a local pointer point to something else, you don't actually change what it points to. For that you need to use the dereferencing operator *:
*val = *((Value*) iter->second.PN);