Callback function: Incompatible argument - c++

I am trying to use callback function in my problem but I got into some troubles. In the sort() function, the parameter &compareType has an error:
Argument of type "bool (Person::*)(const Person& p1, const Person& p2)" is incompatible with parameter of type "compare"`
person.h
class Person
{
public:
bool compareType(const Person& p1, const Person& p2) { return ... };
void sort()
{
...
list->addInOrder(person, &compareType);
...
}
...
}
dlinkedlist.h
typedef bool (*compare)(const Person& p1, const Person&p2);
class dlinkedlist
{
public:
void addInOrder(const Person& person, compare comparefunc)
{
Person person2;
...
comparefunc(person, person2);
...
}
}

bool compareType(const Person& p1, const Person& p2)
is actually of type
bool (Person::*) (const Person&, const Person&)
You have to make your method static to have correct type.

There are mainly three solutions.
You can either:
declare the member method as static
define a function outside the class that is friend of your class (if needed) and use it
The third solution is maybe the most interesting one:
you can use a non-capturing lambda function that, because of the fact that is a non-capturing one, can decay to a pointer to function.
So, as an example, the following lambda is perfectly fine in your case:
[](const Person& p1, const Person& p2) { return true; }
It follows a minimal, working example:
struct A { };
using Fn = bool(*)(const A &, const A &);
void f(Fn fn) {
fn(A{}, A{});
};
int main() {
f([](const A &, const A &){ return true; });
};
As you can see, the lambda automatically decays to a pointer to function, so it's fine to use it in such a case.
Obviously, the solution involving the lambda is not suitable if you need to access private members, of course.

A non-static method is different to a free function or static method. You can see that from the type in the error message:
bool (Person::*)(const Person& p1, const Person& p2)
which is different from the type of a simple function
bool (*)(const Person& p1, const Person& p2)
(intuitively, the non-static method has to somehow get a this pointer, so the compiler has to do something different when calling it).
Note that your compareType shouldn't be a non-static member anyway - you'd have to call it like
personA.compareType(personB, personC)
which doesn't make much sense.
Either make it a static method (so you don't invoke it on an instance of Person)
class Person {
public:
static bool compareType(const Person&, const Person&);
// ...
};
or just make it a free function
bool comparePeople(const Person&, const Person&);

Non static class method implicitly adds reference to this, so your function actually looks like
bool compareType(Person *this, const Person &p1, const Person &p2);
You should declare it as static, and this will not be passed into.

Related

Comparison function inside class [error 2878]: binary '<': no operator found which takes a left hand operand of type

Why I've getting that error? I saw a video running such code and has no error at all. I don't would like to define outside of class. What is wrong?
class Person
{
public:
int age;
string name;
bool operator < (const Person& rhs) { return age < rhs.age; }
};
int main()
{
std::set<Person> my;
Person p{ 10, "Eduardo" };
my.insert(p);
}
You need to mark your operator< as being const so that it can be called on objects of type const Person:
bool operator < (const Person& rhs) const { return age < rhs.age; }
^^^^^
The default Compare template parameter of std::set<Person> is std::less<Person>, which takes const Person& parameters in its operator().
Your operator should be const anyway since it does not modify the members of the Person object it is called on.

Initialize a static member of a class that includes an array?

I have a C++ class with a static data member which is a constant. I added an array to the class definition, and now I get an error when trying to initialize the static member.
Here is the code:
class MyClass
{
int i1;
int i2;
int i3;
//bool b1[2];
//bool b2[2];
public:
//Constructors
MyClass();
MyClass(const int i1In, const int i2In, const int i3In
/*, const bool b1In[2], const bool b2In[2]*/
);
// Copy constructor
MyClass(const Input& rhs);
// Destructor
~MyClass();
// Assignment
MyClass& operator=(const MyClass& rhs);
// Operators
bool operator==(const MyClass& m2) const;
bool operator!=(const MyClass& m2) const;
MyClass& operator++(int/*serves no purpose, but must be included*/);
static const MyClass S;
};
const MyClass S = { 0, 0, 0 /*,{ false,false }, { false,false }*/ };
The above code compiles without error, and the value of S is as expected. However, when I change the class definition to add the arrays b1 and b2 (uncomment two places in the class defn and add two array initializers in the initialization of S), I get the error
"C2440: 'initializing': cannot convert from 'initializer list' to 'MyClass'
note: No constructor could take the source type, or constructor overload resolution was ambiguous".
What is the proper way to define a constant variable of type MyClass that has the indicated values?
Windows 7 Pro, Visual Studio 2015
Have the constructor take the array parameters by constant reference.
MyClass(/*...*/ const bool (&b1In)[2], const bool (&b2In)[2])
const MyClass MyClass::S(/*...*/ { false,false }, { false,false } );
The array-as-parameter syntax is really just a cleverly disguised pointer which is why that didn't work.
Also, your operator++(int) returns a reference. Because that is the post-increment operator, it should return by value.

Creating a set of classes

I'm trying to create a set that can be filled with instances of a class. I thought that a requirement for a set is that elements can be compared, and thus in this case I need to tell my class how they can be compared. I created the following class:
class Myclass
{
public:
Myclass(int i):storedval(i) {}
int getval(){return storedval;}
friend bool operator> (Myclass &first, Myclass &second)
{
return first.getval()>second.getval();
}
friend bool operator< (Myclass &first, Myclass &second)
{
return first.getval()<second.getval();
}
private:
int storedval;
};
But when I try to add instances to a set like this:
Myclass a(50);
set<Myclass> Bunchofclasses;
Bunchofclasses.insert(a);
It gives me a bunch of error text that I think tells me it doesn't understand the > and < operators. How should this be done properly?
You need to pass const references to the comparison function because it should not be allowed to modify the items being compared:
friend bool operator< (const Myclass& first, const Myclass& second)
{ // ^^^^^ ^^^^^
return first.getval() < second.getval();
}
This will require that you make getVal() const as well. This makes it callable on const instances or via const references:
int getval() const {return storedval;}
// ^^^^^
Note that you do not need operator> for the set to work. Less-than is enough.
Strictly speaking, you do not need a friend function here, since you are calling public member functions. The only thing that friend brings here is to allow you to declare a non-member function inside of the class definition.
Elements of a set are immutable, so the set needs to be able to compare const values. So the comparison needs to be:
friend bool operator< (Myclass const &first, Myclass const &second)
// ^^^^^ ^^^^^
(You should probably also do this with operator> and any other non-mutating operations you provide; but set only needs operator<).
Also, in order to access the value of a const object, the accessor also needs to be const:
int getval() const
// ^^^^^

Why i need to use the const function in the Less Traits

why i need to use the const function in the less traits?
for example, why i must use const in Age or ID member function.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
#include <string>
#include <set>
using namespace std;
class Person
{
public:
Person(int id, string name, int age):m_iID(id), m_strName(name), m_iAge(age){};
int Age() const {return m_iAge;}
int ID() const {return m_iID;}
void Display();
friend ostream& operator<<(ostream& out, Person& person);
private:
int m_iID;
string m_strName;
int m_iAge;
};
void Person::Display()
{
cout<<m_iID<<" "<<m_strName<<" "<<m_iAge<<endl;
}
ostream& operator<< (ostream& out, Person& person)
{
out<<person.m_iID<<" "<<person.m_strName<<" "<<person.m_iAge<<endl;
return out;
}
int SumPersonAge(int iSumAge, Person& person)
{
return iSumAge + person.Age();
}
template <typename Type>
void Display(Type t1)
{
cout<<t1<<endl;
}
class LessPerson
{
public:
template <typename Type>
bool operator()(Type& t1, Type& t2)
{
return t1.ID() < t2.ID();
}
};
int main()
{
set<Person, LessPerson> s1;
Person p1(1234, "Roger", 23);
Person p2(1235, "Razor", 24);
s1.insert(p1);
s1.insert(p2);
for_each(s1.begin(), s1.end(), Display<Person>);
}
if i remove the const the keyword in Age or ID function, the compiler will report me Error cannot convert 'this' pointer from 'const Person' to 'Person &'.
The answer is that the set will pass two const reference to Person objects to your comparator, and you cannot call a non-const function on a const variable.
You might be surprised as there seems not to be any const in the declaration of the functor:
struct LessPerson
{
template <typename Type>
bool operator()(Type& t1, Type& t2)
{
return t1.ID() < t2.ID();
}
};
But there is, it is just not explicit in the code. Inside the set implementation there are two const Person& references (call them r1, r2) and a LessPerson comparator (call it compare) and the code does something in the lines of if ( comparator(r1,r2) ). The compiler finds the templated operator() and tries to infer the types ending up with the type substitution: Type == const Person.
Why does the set use const references rather than plain modifiable references? Well, that is a different issue. The set is implemented as a sorted balanced tree, with each node containing the key. Now because a change in the key would break the order invariant, the keys are themselves const objects, ensuring that you cannot break the invariants.
That const keyword means that the function does not modify its object, this. Only const functions may be called from const objects. So, the compiler is telling you that you are trying to call a non-const member function from a const object.
You appear to be avoiding the const keyword, but it creeps in when the library calls your template function:
template <typename Type>
bool operator()(Type& t1, Type& t2)
{
return t1.ID() < t2.ID();
}
Type is passed as const Person.
const is not easy to get rid of without cheating, and it will always creep in. It's better to go with the flow and add const everywhere you take a reference that doesn't change an object (which is most of them).
Because the type passed to LessPerson is const Person.
So basically, LessPerson is roughly
class LessPerson   
{
public:
bool operator()(const Person& t1, const Person& t2)
{
return t1.ID() < t2.ID();
}
};
You can't call non-const methods on const objects. It's a rule of C++.

operator overloading c++

I am trying to preform operator overloading in C++;
for some reason the compiles keeps on giving me the error
error: ‘bool Matrix::operator==(const Matrix&, const Matrix&)’ must take exactly one argument
Now, I know that there is some way to to it with one argument using this, but I understood that by using friend I can do it this way, but it still is not working.
Here is my code,
Thanks in advance.
class Matrix{
public:
Matrix();
friend bool operator==(Matrix &mtrx1,Matrix &mtrx2);
friend bool operator!=(Matrix &mtrx1,Matrix &mtrx2);
protected:
std::vector<Cell> _matrix;
int _row;
int _col;
};
inline bool Matrix::operator==(const Matrix& mtrx1, const Matrix& mtrx2){
/* .......... */
}
The operator== member function is declared as:
class foo {
public:
bool operator==( foo const & rhs ) const;
};
The operator== global function is declared as:
bool operator==( foo const & lhs, foo const & rhs );
Generally, the member function is declared and defined first. Then, the global function is defined in terms of the member function as
Only one between the member function and global function is declared and defined. Having both of them is ambiguous for statements like (1) in the following
foo f1;
foo f2;
bool f1EqualsF2 = (f1 == f2 ); // (1), ambiguous
and in such cases compiler returns error. In g++, the error message looks like
equals.cpp:24: error: ambiguous overload for ‘operator==’ in ‘f1 == f2’
equals.cpp:8: note: candidates are: bool foo::operator==(const foo&) const
equals.cpp:17: note: bool operator==(const foo&, const foo&)
Whenever operator== is done, its recommended to do the corresponding operator!=.
Although you've put the friend declaration inside the class, it's not a member. So the function definition should be a non-member:
inline bool operator==(const Matrix& mtrx1, const Matrix& mtrx2) {...}
You also need to add const qualifiers to the arguments of the declarations, to match those in the definition.
class Matrix{
public:
Matrix();
friend bool operator==(const Matrix &mtrx1, const Matrix &mtrx2);
friend bool operator!=(const Matrix &mtrx1, const Matrix &mtrx2);
protected:
std::vector<Cell> _matrix;
int _row;
int _col;
};
inline bool operator==(const Matrix& mtrx1, const Matrix& mtrx2){
/* .......... */
return true;
}
Pass compilation in Visual Studio 2005.
omit the const qualifier in your friend declaration
don't need Matrix:: in operation== definition
You do it with 2 parameters if you are doing it outside of the class, not as a member function.
As a member function you need only 1 parameter (the other parameter is *this)