Function object, this and constructor

V

vulpes

This similar situation will explain somewhat, what I want to do:

class X {
public:
X() : map_(*this) {}

bool operator() (int a, int b) { return goodStuff(a) <
goodStuff(b); }
int goodStuff(int a) { ... }

private:
map<int, int, X> map_;
};

Why do I want this? Because the goodStuff function is already there
and I don't want to write it twice. This piece of code doesn't work as
one would expect. I also tried doing things like

class X {
public:
X() : map_( ptr_fun(&X::stuff) ) {}

bool stuff(int a, int b) const { return goodStuff(a) <
goodStuff(b); }

private:
map< int, int, binary_function<int, int, bool> > map_;
};

but this works neither. Is there a way to do this thing. The X objects
are a pain to construct (lots of big stuff in 'em) so I don't want to
generate them anymore than I have to. I guess that second could be
made to work if the goodStuff would be static, but it ain't.

This isn't a stopper problem, I know a way around this (problem-
specific), but it stinks. I want to know how to do this "the way it
should be done".
 
A

anon

vulpes said:
This similar situation will explain somewhat, what I want to do:

class X {
public:
X() : map_(*this) {}

bool operator() (int a, int b) { return goodStuff(a) <
goodStuff(b); }
int goodStuff(int a) { ... }

private:
map<int, int, X> map_;
};

So you construct the map<int,int> variable from the X class.
Take a look here what are map constructors expecting:
http://www.cppreference.com/cppmap/map_constructors.html
Why do I want this? Because the goodStuff function is already there
and I don't want to write it twice. This piece of code doesn't work as
one would expect. I also tried doing things like

class X {
public:
X() : map_( ptr_fun(&X::stuff) ) {}

bool stuff(int a, int b) const { return goodStuff(a) <
goodStuff(b); }

private:
map< int, int, binary_function<int, int, bool> > map_;
};

What is ptr_fun?
Here is the same as the previous. You want to construct the map<int,int>
object from ptr_fun (whatever that is)

but this works neither. Is there a way to do this thing. The X objects
are a pain to construct (lots of big stuff in 'em) so I don't want to
generate them anymore than I have to. I guess that second could be
made to work if the goodStuff would be static, but it ain't.

This isn't a stopper problem, I know a way around this (problem-
specific), but it stinks. I want to know how to do this "the way it
should be done".

You message was not clear enough for me to understand what exactly you
want to do.
Why your solution stinks?
 
J

James Kanze

This similar situation will explain somewhat, what I want to do:
class X {
public:
X() : map_(*this) {}
bool operator() (int a, int b) { return goodStuff(a) <
goodStuff(b); }
int goodStuff(int a) { ... }
private:
map<int, int, X> map_;
};
Why do I want this? Because the goodStuff function is already there
and I don't want to write it twice. This piece of code doesn't work as
one would expect.

What would one expect? It's undefined behavior. (I expect that
it will not compile with most implementations. I can't think of
any reasonable implementation of map where the class itself
doesn't contain an instance of the comparator. So what you've
written is that X contains a map which contains an X...)
I also tried doing things like
class X {
public:
X() : map_( ptr_fun(&X::stuff) ) {}
bool stuff(int a, int b) const { return goodStuff(a) <
goodStuff(b); }
private:
map< int, int, binary_function<int, int, bool> > map_;
};
but this works neither. Is there a way to do this thing.

The obvious (but not necessarily good) solution is to replace
the map with a pointer to the map. Alternatively, just about
any form of indirection in the comparator should work:

class X ;
class XCmp
{
public:
XCmp( X const* owner ) ;
bool operator()( int, int ) const ;

private:
X const* myOwner ;
} ;

class X
{
// ...
private:
std::map< int, int, XCmp >
myMap ;
} ;
The X objects
are a pain to construct (lots of big stuff in 'em) so I don't want to
generate them anymore than I have to.

Then you almost certainly don't want to use one directly as
comparator. The actual map uses a *copy* of the object it is
passed in the constructor (or a default constructed instance, if
it isn't passed a comparator).
I guess that second could be
made to work if the goodStuff would be static, but it ain't.

You could probably work out something using boost::bind. The
basic problem is that you have a function with three arguments
(the X and the two ints), and map will want to call it with two,
so you need to use a functional object which contains a pointer
to (or a reference to) the X. And you can't do it with the
standard binders, because the (current) version of the standard
doesn't support functional objects with more than two
parameters.
This isn't a stopper problem, I know a way around this
(problem- specific), but it stinks. I want to know how to do
this "the way it should be done".

"The way it should be done" probably depends on the context, but
most likely involves a comparator object with a pointer to (or a
reference to) the owning X.
 
V

vulpes

What would one expect? It's undefined behavior. (I expect that
it will not compile with most implementations. I can't think of
any reasonable implementation of map where the class itself
doesn't contain an instance of the comparator. So what you've
written is that X contains a map which contains an X...)

Well I kinda expected it wouldn't work. That code is there just
because it explains the situations quickly.

Actually I need a map< Y, int >, where Y is my own class. The REAL
problem is that I just can't (REALLY) write operator< for the class Y,
because this map needs some X object specific knowledge to keep it
together. Therefore I need to use a function object and the class X
already has a nice member function needed elsewhere, which would fit
in quite nicely. Thus I want to use the *this object as the function
object.


To anon:

ptr_fun is a function object adapter from the STL functional library.
It's point is to make it easy to use function pointers with function
objects. I also tried using mem_fun_ref and whatever's there. There
shouldn't be any problems with the constructor calls, there's just
this inconvenient loop of references. I thought that I could
circumvent it with ptr_fun, because the memory address of the member
function should be calculable pretty early. Not early enough I guess
then.

The obvious (but not necessarily good) solution is to replace
the map with a pointer to the map. Alternatively, just about
any form of indirection in the comparator should work:

Well, you know, now I feel a bit embarassed. I was just thinking about
X* pointers all the time and how to put them to the map, never came it
to my mind that of course I can turn the thing upside down. I was
thinking that I have to separate the two somehow and tried it with
that X*.
class X ;
class XCmp
{
public:
XCmp( X const* owner ) ;
bool operator()( int, int ) const ;

private:
X const* myOwner ;
} ;

class X
{
// ...
private:
std::map<int, int, XCmp> myMap ;
} ;

Actually at first after I read your comment, but before reading your
code, I thought of writing

private:
map< int, int, X& >* map_;

which would of course take the problem away because now we don't need
any "gimmick 3" when initializing the variables. I can then
initialize the pointer later on correctly to X::*this. On the other
hand your solution is quite good too. In the end, it's just the
Adapter design pattern, but hey, I'm the one who didn't think of that.
Then you almost certainly don't want to use one directly as
comparator. The actual map uses a *copy* of the object it is
passed in the constructor (or a default constructed instance, if
it isn't passed a comparator).

But I can avoid making that copy by defining the Compare template
parameter as a reference X&: map< int, int, X& > map_;
Done that before with several STL algorithms (eg. for_each) where you
don't want to make copies all the time.

You could probably work out something using boost::bind. The
basic problem is that you have a function with three arguments
(the X and the two ints), and map will want to call it with two,
so you need to use a functional object which contains a pointer
to (or a reference to) the X. And you can't do it with the
standard binders, because the (current) version of the standard
doesn't support functional objects with more than two
parameters.

I was looking at bind1st and bind2nd and cursing at the lack three
parameter analogy in STL. I've had this project of mine scanning
through different boost libraries and their uses (there's definitely
some good stuff, things I've always wanted to do) because I've used
only some of them ever. That boost::bind is just the thing I need
here. Now my problem is to decide which way is the best of the three.
Maybe that boost::bind (using new fancy libraries is always fun...)

Thanks!
 
A

anon

vulpes said:
This similar situation will explain somewhat, what I want to do:

class X {
public:
X() : map_(*this) {}

bool operator() (int a, int b) { return goodStuff(a) <
goodStuff(b); }
int goodStuff(int a) { ... }

private:
map<int, int, X> map_;
};

#include <map>
using namespace std;

class X {
public:
X(){}

bool operator() (int a, int b) { return goodStuff(a) <
goodStuff(b); }
int goodStuff(int a) { return a; }
};

class Y
{
public:
Y():map_(x){}


private:
map<int, int, X> map_;
X x;
};

int main()
{
Y x;
}

Is this good enough for your use?
 
V

vulpes

class X {
public:
X(){}

bool operator() (int a, int b) { return goodStuff(a) <
goodStuff(b); }
int goodStuff(int a) { return a; }
};

class Y
{
public:
Y() : map_(x){}

private:
map<int, int, X> map_;
X x;
};

int main()
{
Y x;
}

Is this good enough for your use?

Well it's fine otherwise, but I'd rather let the class X be the main
character in the plot. Here's why: The class X is actually one of
several concretizations to an interface class and I use the class X
exclusively through that interface. It would be an unnecessary
complication to create a whole facade in front of X. Therefore I
wouldn't use your solution, it's like an inverse Adapter. But at least
there seems to be a slew of ways to do it, if you just keep pressing
the issue.

Thanks for your help. If you want, I'll post my final decision and
code here when I get to it (This evening European time I'd wager).
Someone may benefit from it later on.
 
B

BobR

anon said:
What is ptr_fun?
Here is the same as the previous. You want to construct the map<int,int>
object from ptr_fun (whatever that is)

[ from STL docs ]

- Description -
Ptr_fun takes a function pointer as its argument and returns a function
pointer adaptor, a type of function object. It is actually two different
functions, not one (that is, the name ptr_fun is overloaded). If its
argument is of type Result (*)(Arg) then ptr_fun creates a
pointer_to_unary_function, and if its argument is of type Result (*)(Arg1,
Arg2) then ptr_fun creates a pointer_to_binary_function.

- Definition -
Defined in the standard header <functional>, and in the nonstandard
backward-compatibility header <function.h>.
 

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
474,291
Messages
2,571,476
Members
48,143
Latest member
Manuelevimb

Latest Threads

Top