Member function as parameter of STL algorithm

M

many_years_after

Hi, cppers:

I am studying cpp recently. As is said, member funciton can be as
one parameter of stl algorithm. BUT when I pass member function whose
parameter is instance of the class, it doesn't work. For example:

class Point
{
public:
int x; int y;
Point(int xx, int yy)
{
x = xx;
y = yy;
}
friend ostream& operator<<(ostream& out,const Point& p)
{
out << p.x << " "<< p.y << endl;
return out;
}
bool LargeThan(const Point& p)
{

return (x > p.x)|| ((x==p.x) && (y > p.y));
}
void print()
{
cout << x << " " << y;
}
void printWithPre(const char* s)
{
cout << s << " " << x;
}
};
int main()
{
vector<Point> vec;

for (int i = 0; i < 10; i++)
vec.push_back(Point(i, i));
for_each(
vec.begin(),
vec.end(),
bind2nd(mem_fun_ref(&Point::printWithPre),"hello:")
); //OK

for_each(
vec.begin(),
vec.end(),
mem_fun_ref(&Point::print)); // OK
sort(vec.begin(), vec.end(), mem_fun_ref(&Point::LargeThan)); //
ERROR WHEN COMPILING


return 0;
}

I don't know why it does not work. What's the reasong?
 
J

Juha Nieminen

many_years_after said:
sort(vec.begin(), vec.end(), mem_fun_ref(&Point::LargeThan)); //
ERROR WHEN COMPILING

Member functions cannot be called without an object of the class type.
You can think of member functions as if they took a pointer to an object
of that class type as a hidden parameter. (And this is, in practice,
actually the case. The name of that pointer is called "this" inside the
function.)

What you can do is create a regular function (or a static member
function) which takes two const references of the class type and returns
the result of the comparison, and then give that to std::sort().
(Or you could also create a functor, ie. a class/struct which behaves
like such a function by overloading operator().)
 
R

Robert Bauck Hamar

Juha said:
Member functions cannot be called without an object of the class type.
You can think of member functions as if they took a pointer to an object
of that class type as a hidden parameter. (And this is, in practice,
actually the case. The name of that pointer is called "this" inside the
function.)

What you can do is create a regular function (or a static member
function) which takes two const references of the class type and returns
the result of the comparison, and then give that to std::sort().
(Or you could also create a functor, ie. a class/struct which behaves
like such a function by overloading operator().)

Yes. The idea behind mem_fun_ref() is to create such a functor. It returns
an object, call it o, capable of transforming o(a, b) to o.fun(b) for some
pointer to member function given as argument.
 
R

Robert Bauck Hamar

many_years_after said:
Hi, cppers:

I am studying cpp recently. As is said, member funciton can be as
one parameter of stl algorithm. BUT when I pass member function whose
parameter is instance of the class, it doesn't work. For example:

class Point
{
public:
int x; int y;
Point(int xx, int yy)
{
x = xx;
y = yy;
}
friend ostream& operator<<(ostream& out,const Point& p)

error: ostream not declared. Yes it's easy to fix, but if you want help,
posting compilable code (or in this case, code that has no other errors)
will help.
{
out << p.x << " "<< p.y << endl;

IMHO, you should remove the endl. There are two reasons:
1) endl provokes a flush. If the user wants a flush, the user can flush on
his/her own. 2) endl sends an '\n'. This will make this operator useless in
most cases. Try to use it to output tabular data, for instance.
return out;
}
bool LargeThan(const Point& p)

bool LargeThan(const Point& p) const
{

return (x > p.x)|| ((x==p.x) && (y > p.y));
}
void print()

void print() const
{
cout << x << " " << y;
}

This does exactly what (parts of) operator<<(ostream&, const Point&) does,
and IMO what operator << should have done.
void printWithPre(const char* s)

void printWithPre(const char* s) const
{
cout << s << " " << x;
}
};
int main()
{
vector<Point> vec;

for (int i = 0; i < 10; i++)
vec.push_back(Point(i, i));
for_each(
vec.begin(),
vec.end(),
bind2nd(mem_fun_ref(&Point::printWithPre),"hello:")
); //OK

for_each(
vec.begin(),
vec.end(),
mem_fun_ref(&Point::print)); // OK
sort(vec.begin(), vec.end(), mem_fun_ref(&Point::LargeThan)); //
ERROR WHEN COMPILING

Here, mem_fun_ref returns a functor with

bool operator()(Point& a, const Point& b) const, and this calls
a.LargeThan(b). Not that LargeThan is non-const on a. The standard
specifies:
It is assumed that comp [the comparator] will not apply any non-constant
function through the dereferenced iterator.

On g++ 4.2.0 it compiles only if the comparator is called with two
references to const objects. Is this a bug?
return 0;
}

I don't know why it does not work. What's the reasong?

If a member function doesn't modify the object, consider making it const.
 
I

int2str

Hi, cppers:

I am studying cpp recently. As is said, member funciton can be as
one parameter of stl algorithm. BUT when I pass member function whose
parameter is instance of the class, it doesn't work. For example:

It won't work. std::sort() either needs a predicate function
(functor), or it simply needs the < (less than) operator to work
correctly.

The latter case is the easiest. Let's make your code work...


#include <iostream>
#include <ostream>
#include <algorithm>
#include <vector>

using namespace std;

class Point
{
public:
int x; int y;
Point(int xx, int yy)
{
x = xx;
y = yy;
}
friend ostream& operator<<(ostream& out,const Point& p)
{
out << p.x << " "<< p.y << endl;
return out;
}
bool LargeThan(const Point& p)

bool LargerThan(const Point& p) const // const is IMPORTANT
here...
{

return (x > p.x)|| ((x==p.x) && (y > p.y));
}
void print()
{
cout << x << " " << y;
}
void printWithPre(const char* s)
{
cout << s << " " << x;
}

bool operator< (const Point& p ) const
{
return !LargerThan(p);
}
};

int main()
{
vector<Point> vec;

for (int i = 0; i < 10; i++)
vec.push_back(Point(i, i));
for_each(
vec.begin(),
vec.end(),
bind2nd(mem_fun_ref(&Point::printWithPre),"hello:")
); //OK

for_each(
vec.begin(),
vec.end(),
mem_fun_ref(&Point::print)); // OK
sort(vec.begin(), vec.end(), mem_fun_ref(&Point::LargeThan)); //
ERROR WHEN COMPILING

Now that the operator is defined, simply use:

sort(vec.begin(), vec.end());
 
J

James Kanze

many_years_after said:
I am studying cpp recently. As is said, member funciton can be as
one parameter of stl algorithm. BUT when I pass member function whose
parameter is instance of the class, it doesn't work. For example:
class Point
{
public: [...]
bool LargeThan(const Point& p) [...]
void print() [...]
};
int main()
{
vector<Point> vec;

[...]
for_each(
vec.begin(),
vec.end(),
mem_fun_ref(&Point::print)); // OK
sort(vec.begin(), vec.end(), mem_fun_ref(&Point::LargeThan)); //
ERROR WHEN COMPILING
return 0;
}
I don't know why it does not work. What's the reasong?

mem_fun_ref doesn't work when the function argument is a
reference. I'd consider it a defect in the standard. At any
rate, the next version of the standard will contain some more
advanced tools for this sort of thing, based on boost::bind. In
the meantime, use boost::bind.
 
P

Pete Becker

mem_fun_ref doesn't work when the function argument is a
reference. I'd consider it a defect in the standard. At any
rate, the next version of the standard will contain some more
advanced tools for this sort of thing, based on boost::bind. In
the meantime, use boost::bind.

Also, std::mem_fn (which I think is also in boost) is a simpler
template than bind, pretty much a drop-in replacement for mem_fun and
mem_fun_ref. For details, see chapter 7 of my book, "The Standard C++
Library Extensions".
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top