C++ List sort function - c++

I don't know how to correctly implement the a sort for a list in C++. I am getting the build errors:
'Ranker::compare': function call missing argument list; use '&Ranker::compare' to create a pointer to member
How do I correctly implement my sort function for the list?
Ranker.h:
list<Competitor*> sorted;
Ranker.cpp:
bool Ranker::compare(Competitor* first, Competitor* second) {
if (first->getTime() < second->getTime())
return true;
else
return false;
}
int Ranker::addList(Competitor* starter) {
sorted.push_back(starter);
sorted.sort(compare);
}

Just make rankor a simple functor:
struct Compare
{
bool operator()(Competitor* first, Competitor* second) const {
return first->getTime() < second->getTime();
}
};
// STUFF
sorted.sort(Compare());
Or if you have C++11
sorted.sort([](Competitor* first, Competitor* second) {
return first->getTime() < second->getTime();
});

Ranker::compare() is a member function. Member functions are tied to instances. Try using either a static method or a "free" function.

The function Ranker::compare() actually has three arguments: In addition to the two Competitor objects, it also takes an implicit pointer to the object as parameter. However, the binary predicate passed do std::list<...>::sort() only takes two parameters.
The easiest fix is probably to make the function a static member. Not, however, that this is probably not the fastest approach because function pointers can rarely be inlined. If you want to reduce the function call overhead, you might want to encapsulate the logic into a a suitable function object:
struct RankerCompare {
bool operator()(Competitor const* first, Competitor const* second) const {
return first->getTime() < second->getTime();
}
};
...
sorted.sort(RankerCompare());
BTW, a Boolean doesn't become more Boolean by returning true or false from a conditional statement! It is perfectly OK to return a Boolean value directly!

Related

Function Pointers by Reference

Good Day everybody, I am creating a List class in order to be able to manipulate data like in python, but in c++.
I came up with an idea. Basically a method that goes through every node, and deletes it if it meets a specific condition. But I wanted that condition to be determined by the user of the library, so I implemented a pointer to a bool function, that takes one template data (same type as the List) as its only parameter.
So far, I managed to run this...
.h file:
int delIf(bool (*)(T));
.cpp file:
template <typename T>
int List<T>::delIf(bool (*ptr)(T)){
int tot=0;
T aux;
for (int i=0;i<tam;i++)
{
aux=(*this)[i]; //Ive overloaded the [], and it works fine
if ((*ptr)(aux))
{
tot++;
this->del(i);
}
}
return tot;
}
main.cpp:
#include <iostream>
#include "lists.cpp"
using namespace std;
bool check(int);
int main()
{
List<int> a;
for (int i=0;i<10;i++)
a.push(i);
a.delIf(&check);
return 0;
}
bool check(int a){
if (a%2==0)
return true;
else
return false;
}
This works fine, however, I was wondering if its possible to overload the delIf method so that it takes not a pointer to a function as parameter, but a reference to it, so the user of the library could call:
delIf(check); //No '&' required
Instead of the
delIf( & check);
That is currently mandatory. Ive tried changing the prototype to something like:
int delIf( (bool (*)(T)) & );
but I keep getting errors.
Thanks in Advance Everybody.
Your premise is false. You don't need an & in front of a function to pass it to delIf. The name of a function decays into a pointer to the function almost everywhere it is used in an expression. (Including when you call the function!) In fact, the only place it doesn't is when it is used as an argument to & - so
func
&func
have exactly the same type and value.
Having said that, yes you can pass a reference. First rule of pointers to functions - write a typedef
typedef bool pred_t(T);
void delIf( pred_t& pred );
But! I strongly encourage you to write delIf as a function template, and allow anything which can be called with a T, and has a function result which can be implicitly converted to bool.
template <typename Pred>
void delIf(Pred pred) {
...
}
That will allow use with capturing lambdas, and functors in general.
Also, what is this CPP file of which you speak? Templates have to be implemented in the header file. See the answers to this question.
(Note: "Pred" is short for "predicate" which is what the standard calls this sort of function.)

c++ remove custom object from vector : std::remove_if': no matching overloaded function found

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());
}

remove_if: Predicate error when passing a function returning bool

I have this pre-defined function.
void attack(std::vector<GameObject*> objects, unsigned damage) {
for (GameObject* object : objects) {
object->takeDamage(damage);
auto isDead = object->isDead();
objects.erase(std::remove_if(objects.begin(),objects.end(),isDead), objects.end());
}
}
This is my isDead function
bool isDead() const {
if (destructed) {
std::cout << "memory error" << std::endl;
}
return life <= 0;
}
This is the error I keep getting. Have tried a lot of things, but not at all able to figure this one out. Any help appreciated!
error: expression cannot be used as a function
{ return bool(_M_pred(*__it)); }
isDead is a variable in the function. You can't use it as an argument to remove_if.
You can't use a regular member function as argument to std::remove_if either. Use a lambda function instead.
Don't erase objects from a container while you are iterating over it using a range for loop.
Change the argument to attack to be a reference. Otherwise, you will be removing objects from a copy, not the original container.
Here's an updated version of attack:
void attack(std::vector<GameObject*>& objects, unsigned damage)
{
for (GameObject* object : objects)
{
object->takeDamage(damage);
}
objects.erase(std::remove_if(objects.begin(),objects.end(), [](GameObject* object){return object->isDead();}), objects.end());
}
isDead() is a member function of one of your classes, which is exactly why it doesn't work: you did not supply this pointer (object instance) for it to be called on. Oh, and the predicate for remove_if must have exactly one argument of the type objects::value_type.
Do this instead:
objects.erase(std::remove_if(objects.begin(),objects.end(),[](GameObject* object){return object->isDead()), objects.end());

Sorting vector of instances

I am currently taking a coding class at university and they have VERY specific requirements for the homework assignments.
For this week we have a class called Npt that represents a Nobel Prize winner. This class contains, amongst other things, the Name, the year of the prize and the field of the winner.
Now we should make another class, Nobelpreise, that contains a container for instances of said Nobel prize winner class. We are supposed to sort the elements of that container by the year of the Nobel Prize.
I wasn't able to use the std::sort function with a custom comparator correctly. This is what my code roughly looks like:
class Nobelpreise
{
private:
int numb;
vector<Npt> xx;
public:
Nobelpreise(){numb=0;}
void add(Npt &n1){xx.push_back(n1);numb++;return;}
Npt get_nobel(int i) {return xx[i];}
vector<Npt> get_xx() {return xx;}
int get_numb(){return numb;}
~Nobelpreise(){}
bool mycomp(Npt N1, Npt N2) {return (N1.get_jverl()<N2.get_jverl());}
};
The method get_jverl() comes from the Npt class and just returns the year.
Now the sort function always gives back an error saying that:
sort(Npl.get_xx().begin(), Npl.get_xx().end(), Npl.mycomp)
requires two arguments. Shouldn’t they be provided by the sort function?
I have also tried to overload the < operator which does not seem to work either.
edit1: added end() and removed the () from Npl.mycomp
edit2: we are required to make the comparator function a member of the class
Make your method mycomp static, and write a method which does the sort job.
class Nobelpreise
{
private:
int numb;
vector<Npt> xx;
public:
Nobelpreise(){numb=0;}
~Nobelpreise(){}
vector<Npt>& get_xx() {return xx;}
static bool mycomp( const Npt &N1, const Npt &N2 ) { return N1.get_jverl() < N2.get_jverl(); }
//^^^^^^
void Sort() { std::sort( xx.begin(), xx.end(), &mycomp ); }
};
The method Npt::get_jverl has to be const
returntype get_jverl() const { return ...; }
If you do the sorting outside your class note that you have to return a reference to your vector in your method: vector<Npt>& get_xx() {return xx;}
sort(Npl.get_xx().begin(), Npl.get_xx().end(), &Nobelpreise::mycomp)
Firstly, we'll fix the error that you're fetching two instances of the list:
sort(Npl.get_xx().begin(), Npl.get_xx().end, Npl.mycomp());
Replace with
auto v = Npl.get_xx();
std::sort(v.begin(), v.end(), Npl.mycomp());
I've added () to v.end, too, as we want to call it. However, we don't mean to call Npl::mycomp() here - std::sort wants to receive a function, not the return value:
auto v = Npl.get_xx();
std::sort(v.begin(), v.end(), Npl::mycomp);
This still won't work, as Npl::mycomp is an instance method, and std::sort won't call it with an object pointer for this. As it's implementation doesn't use this, it can be made a static method. Better still, it doesn't use any of the private members, so can be made a free function, outside of any class:
// I've renamed this to say what it does
bool year_precedes(const Npt& a, const Npt& b) {
return a.get_jverl() < b.get_jverl();
}
class Nobelpreise; // make the full declaration available
// for the following to compile
// I've made this a nonmember, too, as it only uses public methods
vector<Npt> sorted_prizes(const Nobelpreise& p)
{
auto v = p.get_xx();
std::sort(v.begin(), v.end(), year_precedes);
return v;
}
That should be enough to help you on your way.
You didn't say which version of C++, but assuming C++11 here's a more modern approach (compared to the two answers that are already here). Your requirements don't mention needing the comparator for anything else, so rather than write a comparator, you can do this:
std::sort(Npl.get_xx().begin(), Npl.get_xx().end(), [](const Npt& lhs, const Npt& rhs) {
return lhs.get_jverl() < rhs.get_jverl()
});
You could put this code in the Sort method of the Nobelpreise class as Rabbid suggests.
Compared to the other approaches here, I'd argue it makes the code more readable as you can see inline what is being compared, instead of having to jump to a new function just to read one more line of code (assuming of course that function is not being used anywhere else). It also makes the code faster because you are passing a lambda rather than a function pointer, but you shouldn't necessarily worry about that at this stage.

Passing a bool as a param. C++

what I am trying to do is an example below.
let's first define a bool.
bool cat = {false};
lets make a fake bool here.
bool setcat(bool booltoset)
{
booltoset = true;
return booltoset;
}
now lets call it with cat.
printf("cat is %s", cat?"true":"false"); //set cat as false.
my question is; is it possible to actually pass a bool through an argument than set that bool?
You need to pass by reference, i.e.:
void setcat(bool& booltoset)
{
booltoset = true;
}
Any function argument is just a variable with scope identical to the function body. If it's an ordinary automatic variable, then changing it has not effect on the caller. This is sometimes useful: you can actually use the arguments, for example:
template<typename F>
void for_each(noexcept_it i, const noexcept_it end, const F &f) noexcept(noexcept(f))
{
for(; i!=end; ++i) f(i); // use i as iteration variable.
}
though the compiler will optimise such things anyway in most cases.