What is this class for ?
class EqualTo {
private:
int target;
public:
EqualTo(int i) : target(i) {}
bool operator()(const int& i) const {
return i == target;
}
};
I have this class in a homework and they have used it with the find function just like :
it = list.find(EqualTo(3));
thanks
It's a functor; that is, an object that can be called like a function. It's more flexible than a function, since it can also contain state and use that when it's called. Here's an example of how to use it directly:
EqualTo is5(5); // Object to test whether numbers are 5
assert(is5(5)); // Returns true: value is 5
assert(!is5(42)); // Returns false: value is not 5
In this case, it takes a single value and returns a boolean to tell you whether that value satisfies some condition; a functor that does that is known as a predicate.
it = list.find(EqualTo(3));
This example uses a predicate to find an element in a container which matches the condition. In this case, it gives you an iterator pointing to the first element that equals 3.
Related
Suppose I have the following class
class Human
{
public:
Human();
Human(string,int);
virtual ~Human();
string getName();
protected:
private:
string name;
int staj;
};
I have created list with 2 elements that I pushed in
list<Human> mylist;
Human x ("Mike",13);
Human y("pavlek",33);
I am trying to remove if there is element with name "Mike",I tried removing it like this :
for(list<Human>::iterator it=mylist.begin();it!=mylist.end();++it)
{
if(it->getName()=="Mike")
{
mylist.remove(it);
cout<< "removed";
cout<<it->getName();
}
}
However I get error at passing the value to the remove() function,what should I exactly pass in order to delete this element from the list?
You have simply mistaken erase and remove. According to the C++ reference, remove is used to remove from the list all elements whose values are equals to the given parameter. On the other hand, erase removes a single element given its position or a range of elements given the start and end positions.
If you only need to delete the first element containing "Mike" as its name, simply do something like this:
for(list<Human>::iterator it=mylist.begin();it!=mylist.end();++it)
{
if(it->getName() == "Mike")
{
mylist.erase(it);
break;
}
}
Please notice that after using erase, your iterator will be invalidated. You can circumvent it by using the returned value of erase, which is the next valid iterator value. This detail is important if your list might contain multiple elements whose name is "Mike".
Matheus Portela's solution was the old C++98 method. It's a lot easier now:
mylist.remove_if( [](Human const& h){return h.getName()=="Mike";} );
The condition here is [](Human const& h){return h.getName()=="Mike";}. That is a lambda expression which returns true if the Human h should be removed. You can test any other property or combination of properties there. The { } part of the lambda is a real function body; you could even have for-loops in there:
Other examples:
mylist.remove_if( [](Human const& h){return h.getName().size() > 4; } );
mylist.remove_if( [](Human const& h) {
for (char c: h.getName())
if (c=='i') return true; // remove if name contains an i
return false; } );
Mind you, the latter would be easier with std::any_of.
In my project there is a vector
std::vector<std::shared_ptr<MovingEntity>>gameObjects;
Which I want to delete elements from if they meet the criteria.
Method to delete elements:
void GameWorld::catchBees()
{
auto q = std::remove_if(bees.begin(), bees.end(), beeToClose);
bees.erase(q);
}
Method beeToClose:
bool GameWorld::beeToClose( const MovingEntity & bee)
{
std::shared_ptr<Beekeeper> keeper = std::static_pointer_cast<Beekeeper>(m_beekeeper);
if (bee.getConstPosition().distanceTo(m_beekeeper->getPosition()) > keeper->getCatchDistance())
{
return true;
}
return false;
}
When I try to compile the code I get some errors which I tried to understand:
'GameWorld::beeToClose': non-standard syntax; use '&' to create a
pointer
Not sure why this message is given
'std::remove_if': no matching overloaded function found
I did not declare beeToClose right?
'q': cannot be used before it is initialized SDLFramework
q is not initialized because:
std::remove_if(bees.begin(), bees.end(), beeToClose);
does not run correct?
How can I remove a std::shared_ptr correctly from a vector correctly when meeting some criteria?
The syntax for forming a pointer to member function is &ClassName::FunctionName. So you need &GameWorld::beeToClose for a pointer to the beeToClose member function. In your case, you should use a lambda from which you call that function
auto q = std::remove_if(bees.begin(), bees.end(),
[&](shared_ptr<MovingEntity> const& bee){ return beeToClose(bee); });
Also, you're using the wrong vector::erase overload, you want the one that erases a range of elements, not the one that erases a single element.
bees.erase(q, bees.end());
The vector contains std::shared_ptr<MovingEntity> elements, so beeToClose() needs to accept a const std::shared_ptr<MovingEntity> & parameter as input, not a const MovingEntity & parameter. Also, beeToClose() appears to be a non-static class method that accesses a non-static class member (m_beekeeper), so you can't just pass beeToClose() directly to std::remove_if() as it does not have access to the calling object's this pointer, but you can wrap it in a lambda to capture the this pointer.
Try this:
void GameWorld::catchBees()
{
auto q = std::remove_if(bees.begin(), bees.end(),
[this](const const std::shared_ptr<MovingEntity> &bee) {
return this->beeToClose(bee);
}
);
bees.erase(q, bees.end());
}
bool GameWorld::beeToClose(const std::shared_ptr<MovingEntity> &bee)
{
std::shared_ptr<Beekeeper> keeper = std::static_pointer_cast<Beekeeper>(m_beekeeper);
return (bee->getConstPosition().distanceTo(m_beekeeper->getPosition()) > keeper->getCatchDistance());
}
You might also consider moving the distance calculation into Beekeeper instead:
bool GameWorld::beeToClose(const std::shared_ptr<MovingEntity> &bee)
{
std::shared_ptr<Beekeeper> keeper = std::static_pointer_cast<Beekeeper>(m_beekeeper);
return !keeper->isInCatchDistance(bee);
}
bool Beekeeper::isInCatchDistance(const std::shared_ptr<MovingEntity> &bee)
{
return (bee->getConstPosition().distanceTo(getPosition()) <= getCatchDistance());
}
I have a problem using the std::map, specifically when using find.
I have the following code.
class MyClass
{
update(const QVariant&);
QVariant m_itemInfo;
std::map<QVariant, int> m_testMap;
}
void update(const QVariant& itemInfo)
{
if(m_itemInfo != itemInfo)
{
// The items are not equal
m_itemInfo = itemInfo;
}
if(m_testMap.find(itemInfo) == m_testMap.end())
{
// TestMap doesnt contain key itemInfo.
m_testMap.insert(std::make_pair(itemInfo, 1));
}
// More code
}
The function update is called several times (with different itemInfo objects) in my code. Now when I start to debug it, I see that the first time update is called, both the first and the second if loop are entered. So far so good. However the second time update is called I do see that the first if loop is called, but the second is skipped! What am I missing here?
I guess the problem that the first and second QVariants that you pass to your Update method have different type (for example, bool and uint). std::map::find doesn't use !=operator to compare keys, it uses operator < (less) by default. If two compared QVariant values have different types operators != and < may work contradictory.
std::map::find compares keys in the following way:
Two keys are considered equivalent if the container's comparison object returns false reflexively (i.e., no matter the order in which the elements are passed as arguments).
i.e. std::map::find considers that v1 is equal to v2
if(!(v1<v2) && !(v2>v1)) { //is TRUE !!!
}
To solve your problem, you should define a less comparison for std:map.
class QVariantLessCompare {
bool operator()(const QVariant& v1, QVariant& v2) const {
// ==== You SHOULD IMPLEMENT appropriate comparison here!!! ====
// Implementation will depend on type of QVariant values you use
//return v1 < v2;
}
};
And use QVariantCompare in a such way:
std::map<QVariant, int, QVariantLessCompare> m_testMap;
A more paradigmatic solution is to use QMap which correctly implements the comparison of most QVariant types. It won't do userTypes() out of the box, but this still might suit your application.
A cleaner version of the solution proposed by Володин Андрей, that builds, might look like:
struct QVariantLessCompare {
bool operator()(const QVariant& v1,const QVariant& v2) const
{
return v1.toInt() < v2.toInt();
}
};
Sorry for the format, I never really posted to a forum like this, so I have to learn the how to a bit.
My problem is:
I'm writing a template class, and I'd like to access my containers via multiple kind of [] operators. I read a bit in this subject, so I've been able to make one overloading, but I need some more:
So in my header file, relevant things about my container:
template <class T>
class version_controlled_vector
{
int rev;
bool vector_state_changed;
std::vector< std::string > revision;
std::vector< std::vector<T> > v;
//first one works ok, im satisfied with it:
std::vector<T>& operator[] (const int idx)
{
return v[idx];
}
//im not sure how to define the further one(s?):
T& operator[](const int idx2) const
{
return v[idx2];
}
//...and ofc some other code
};
//to have these usages at my main.cpp:
version_controlled_vector<int> mi;
version_controlled_vector<std::string> ms;
//this works, and i d like to keep it,
5 == mi[ 0 ][ 0 ];
//and i d like to have these two usages too:
//getting the first character of the stored string:
'H' == ms[ 0 ][ 0 ]; // with the first overload from the header ms[0][0][0]
works to get the first character of the string for eg "Hello"
but, i have to use the ms[0][0] format to achieve this
//and this:
4 == mi[ 0 ]; // i d like this as if it d behave like 4 == mi[0][0];
I don't really get how can I use the single[] when I made an overload to use the [][]
The only solution I have read about is maybe const-overloading, but I'm not sure at all, I'm quite a weakie.
Thanks for ideas!
I think you are muddying the interface of the class. The expectations from the class are:
Get the i-th value from the j-th version.
Get the i-th value from the latest version.
Get the j-th version.
You have the option of using the overloaded operator[] function to get those values but, it will be better to have functions that reflect the interface.
// Get the versionIndex-th version.
std::vector<T>& getVersion(int versionIndex);
// Get the itemIndex-th value from the versionIndex-th version.
T& getItem(int versionIndex, int itemIndex);
// Get the itemIndex-th value from the latest version.
T& getItem(int itemIndex);
Then, the implementation would be simpler and less confusing.
std::vector<T>& getVersion(int versionIndex)
{
// Make sure to add out of bound checks
return v[versinIndex];
}
T& getItem(int versionIndex, int itemIndex)
{
// Make sure to add out of bound checks
return v[versinIndex][itemIndex];
}
T& getItem(int itemIndex);
{
// Make sure to add out of bound checks
return v.back()[itemIndex];
}
Given these, the only operator[] that makes sense, at least to me, is one that returns the i-th value from the latest version.
T& operator[](int itemIndex);
{
// Make sure to add out of bound checks
return v.back()[itemIndex];
}
It's a bit tricky one, you need to realise that when you write
version_controlled_vector<int> mi;
5 == mi[0][0];
during the second fetch you're no longer accessing your version_controlled_vector class but the inner property of it and it's type is std::vector<T> which has its own subscript operator that you call in the second [0].
To control the subscript operator of the second fetch you need to create another class that derives from std::vector<T> and has overloaded subscript operator. Then you should use this class instead of the std::vector in the implementation of version_controlled_vector.
i have to sort a vector. The vector contains pointers to objects of class "student".
the rating metric looks like this:
best finalgrade
if same finalgrade, less attempts
if same attempts, less id
students with 0 attempts are worse than students with 2 attempts and finalgrade 5, sort students with 0 attempts by less id
student looks like this:
private:
std::string name_;
int id_;
int attempts_; //max 2, if 0, exam not taken
int grade1_;
int grade2_;
int finalGrade_; // grade 5 for failed exam but still better than 0 attempts in rating
my problem is that i dont know how to handle attempts. because best number of attempts is 1 and its better than 2 attempts. but 2 attempts are better than 0 in the rating.
i hope you understand my problem and can help me. thx :)
There is a function available in the STL, called std::sort Which can take a comparator function, (either a function pointer, or a function object).
The comparator function has to return a boolean that says whether the first element should appear strictly before the second element.
Here's what I came up with for the comparator:
struct compare_student {
inline bool
operator() (Student *left, Student *right) const
{
if(left->attempts_ == 0 && right->attempts_ == 0)
return left->id_ < right->id_;
else if(left->attempts_ == 0)
return false;
else if(right->attempts_ == 0)
return true;
return
left->finalGrade_ < right->finalGrade_ || // Compare final grade
left->finalGrade_ == right->finalGrade_ && ( // If final grade same:
left->attempts_ < right->attempts_ || // Compare attempts
left->attempts_ == right->attempts_ && ( // If attempts same:
left->id_ < right->id_ // Compare id's
)
);
}
};
Obviously all your fields are private, so you will need to use their accessor methods rather than just accessing them directly, but here's how you use it:
vector<Student *> students {...};
std::sort(students.begin(), students.end(), compare_student{});
std::sort is not stable, this means if two elements are considered equal, then it is not necessarily the case that they will keep their relative order, which may be important to you. If it is, then there is also a function called std::stable_sort which does have such a guarantee, and is used in exactly the same way:
std::stable_sort(students.begin(), students.end(), compare_students{});
EDIT Notes on the implementation
compare_students is a class that has only one, public member, so rather than do this:
class compare_student {
public:
...
};
I shortened it to this:
struct compare_student {
...
};
(the two are equivalent in C++, a struct is just a class with default public access.)
Then as to what inline bool operator() means.
inline is a hint to the compiler that this function can be inlined, that is to say, replace the call with the code itself.
bool is the return type of the function.
operator() is the name of the function, It is a special-case function that gets called when you treat an object like a function:
Student *a, *b;
compare_student comparator {};
comparator(a, b); // calls comparator::operator()(a, b)
Sounds like the first line of your comparison function should be
if (left.attempts_ == 0)
From there, check whether right.attempts_ == 0 as well. If yes, check the IDs.
If no, then right has a grade and left doesn't, right is better.
Continue on with the rest of the rules. Eventually you can use rules like if (left.attempts_ < right.attempts_) but only after you've dealt with 0 attempts.