Pointers to member functions are NOT useless

F

Francesco S. Carta

They don't have to belong to the same class, although the
classes do have to be related by inheritance.

And there's no real "offset" involved. There are two common
techniques for implementing them: in the most obvious, the
pointer stores either the actual address of the function (if
non-virtual) or the index into the vtable (if virtual), some
means of distinguishing between the two, and any correction
necessary to the this pointer. Alternatively, the compiler
generates a trampoline function, which does whatever is
necessary, and stores a pointer to it.

I knew my description was imperfect at least ;-)

Thanks for the correction.
A more frequent approach to this problem involves using an
instance of a forwarding class.

The most frequent use of pointers to member functions is in
instantiating templates, where the pointer to member function is
in fact resolved at compile time.

Would you please post a small example or a pointer to some resource?
I've searched for "forwarding class" but I just found stuff about
forward declarations... is that a pattern?

Also the usage of pointers to member functions in order to instantiate
templates is unknown to me, a small snippet (or again a reference) to
realize what it is all about would be more than welcome.
Some early GUI frameworks made extensive use of them for
callbacks.

I'm starting to suspect there is something wrong with my fixation with
interfaces, GUIs and moreover with the fact that there are a lot of "old
ideas" in my mind even though I never really inspected or studied old
pieces of code... maybe that's just the "normal level" one comes to when
trying to work things out by oneself.
 
J

Jonathan Lee

Have you tried to uncomment the macro for allowing the inline functions?
I think it would show a significant gain to the advantage of your
version (the switch one).

I tried with and without, but the difference was still negligible and
probably not statistically significant given the accuracy of the
clock.
Of course, this is also with using -O3 -march=native, with and without
PGO on GCC. I thought this was fair considering anybody optimizing
code
would do as much.

--Jonathan
 
F

Francesco S. Carta

I tried with and without, but the difference was still negligible and
probably not statistically significant given the accuracy of the
clock.
Of course, this is also with using -O3 -march=native, with and without
PGO on GCC. I thought this was fair considering anybody optimizing
code
would do as much.

I've tried it with all optimizations too, but, as I said above, the
switch version saves one third of the cycles enabling inline functions
(in the very case of my test example, ~1000 clocks against ~1500)...
what is going on differently in our two machines?
 
J

James Kanze

Would you please post a small example or a pointer to some resource?
I've searched for "forwarding class" but I just found stuff about
forward declarations... is that a pattern?

I'm not sure that "forwarding class" is the right name. It's
a "pattern" that is a lot older than patterns, and might not
have a name. It's basically similar to the Observer pattern,
however.
Also the usage of pointers to member functions in order to
instantiate templates is unknown to me, a small snippet (or
again a reference) to realize what it is all about would be
more than welcome.

Check out the documentation of boost::bind. A frequent idiom is
to have a collection of objects, and do something like:
element = std::find_if(c.begin(), c.end(),
boost::bind(&Type::name, _1) == target);
This supposes a collection c of type Type, which has a member
function name which returns something comparable with some
variable target.

(Long before templates were introduced into the language, we
were doing similar things with macros.)
 
F

Francesco S. Carta

I'm not sure that "forwarding class" is the right name. It's
a "pattern" that is a lot older than patterns, and might not
have a name. It's basically similar to the Observer pattern,
however.


Check out the documentation of boost::bind. A frequent idiom is
to have a collection of objects, and do something like:
element = std::find_if(c.begin(), c.end(),
boost::bind(&Type::name, _1) == target);
This supposes a collection c of type Type, which has a member
function name which returns something comparable with some
variable target.

(Long before templates were introduced into the language, we
were doing similar things with macros.)

Thank you for the additional information, now your previous post is
clearer to me.
 
J

Juha Nieminen

Francesco S. Carta said:
Hi there,
after reading an article complaining that pointers to member functions
are misconceived in C++, and after reading a comment about them saying
that they happen to be a rarely necessary feature - if ever necessary at
all - I decided to investigate them to see how I could take advantage of
them, and I also decided to post this message to get the group's feedback.

While I certainly don't use pointers to member functions in a regular
basis, I have had situations where they have been quite useful.

For a relatively large project, which consisted of many command-line
utility programs, I needed an easy way of having a common command-line
parameter interpreter which supported parameters common to all the program,
and where it would be as easy as possible to add new parameters.

After many trial-and-error rounds, I ended up with a solution which,
I think, was the cleanest and easiest. If you wanted to add eg. two new
command-line parameters which modify the same variable, you would do it
something like this:

class MyCLI: public CommandLineInterpreter
{
bool someOption;

public:
MyCLI(): someOption(false)
{
addOption("-x", &MyCLI::xOption, "Description of -x");
addOption("-y", &MyCLI::yOption, "Description of -y");
}

bool xOption()
{
someOption = true;
return true;
}

bool yOption()
{
someOption = false;
return true;
}
};

int main(int argc, char* argv[])
{
MyCLI cli;
if(!cli.parse(argc, argv)) return 1;
...
}

The actual implementation of the CommandLineInterpreter::addOption()
function is a bit complicated because it has to be templatized, but its
usage is pretty simple, as demonstrated above. Without support for member
function pointers, it would be quite more complicated.

Naturally CommandLineInterpreter also provided utility functions for
the derived class to use (eg. to retrieve subsequent command-line
parameters, if it needed them, etc.)
 
F

Francesco S. Carta

Francesco S. Carta said:
Hi there,
after reading an article complaining that pointers to member functions
are misconceived in C++, and after reading a comment about them saying
that they happen to be a rarely necessary feature - if ever necessary at
all - I decided to investigate them to see how I could take advantage of
them, and I also decided to post this message to get the group's feedback.

While I certainly don't use pointers to member functions in a regular
basis, I have had situations where they have been quite useful.

For a relatively large project, which consisted of many command-line
utility programs, I needed an easy way of having a common command-line
parameter interpreter which supported parameters common to all the program,
and where it would be as easy as possible to add new parameters.

After many trial-and-error rounds, I ended up with a solution which,
I think, was the cleanest and easiest. If you wanted to add eg. two new
command-line parameters which modify the same variable, you would do it
something like this:

class MyCLI: public CommandLineInterpreter
{
bool someOption;

public:
MyCLI(): someOption(false)
{
addOption("-x",&MyCLI::xOption, "Description of -x");
addOption("-y",&MyCLI::yOption, "Description of -y");
}

bool xOption()
{
someOption = true;
return true;
}

bool yOption()
{
someOption = false;
return true;
}
};

int main(int argc, char* argv[])
{
MyCLI cli;
if(!cli.parse(argc, argv)) return 1;
...
}

The actual implementation of the CommandLineInterpreter::addOption()
function is a bit complicated because it has to be templatized, but its
usage is pretty simple, as demonstrated above. Without support for member
function pointers, it would be quite more complicated.

Naturally CommandLineInterpreter also provided utility functions for
the derived class to use (eg. to retrieve subsequent command-line
parameters, if it needed them, etc.)

That's another interesting usage of pointers to member functions, thank
you for posting it Juha.

If I am not asking for too much, I'd like to see the complete
implementation.

If you feel that it would be too long for posting it here you could send
me an email, but if it happens to be something you're not allowed to
disclose no problem, that was just an additional curiosity of mine :)
 
J

Juha Nieminen

Francesco S. Carta said:
If I am not asking for too much, I'd like to see the complete
implementation.

Well, the project is open source (and done for academic purposes) so,
it's available. The documentation can be found in the sections 8 and 9
here (starting from page 41):
http://www.cs.tut.fi/ohj/VARG/TVT/TVT_v3.0_classes.pdf

The source code can be found at http://www.cs.tut.fi/ohj/VARG/TVT/

(Disclaimer: I wrote that code almost 10 years ago, and my
understanding or programming in general and C++ in particular was
not as advanced as it is today, so if I examined That code today,
I would probably find some horrible solutions which I wouldn't be
very proud of and would definitely implement differently today. Hence
the code might not be the best example of high-quality C++ out there.)
 
F

Francesco S. Carta

Well, the project is open source (and done for academic purposes) so,
it's available. The documentation can be found in the sections 8 and 9
here (starting from page 41):
http://www.cs.tut.fi/ohj/VARG/TVT/TVT_v3.0_classes.pdf

The source code can be found at http://www.cs.tut.fi/ohj/VARG/TVT/

Thanks for the links :)
(Disclaimer: I wrote that code almost 10 years ago, and my
understanding or programming in general and C++ in particular was
not as advanced as it is today, so if I examined That code today,
I would probably find some horrible solutions which I wouldn't be
very proud of and would definitely implement differently today. Hence
the code might not be the best example of high-quality C++ out there.)

Oh, no problem, it's just for satisfying my curiosity - heck, I'll need
some good time just to get the whole picture ;-)
 
V

Vladimir Jovic

Öö Tiib said:
For loosely coupling something.

For example typical silly observer pattern implementation expects my
observer to have virtual handleEvent(Observed& ref) method. Virtual
from IObserver base interface. Why? Looks like direct translation from
java with no brain applied. I can just boost:bind any member function
as an observer functor. Only limit is that it has to have unique
member function name in class (may not have overloads).

That way i need no useless interface base classes and virtuals and lot
of other bloat and nuisance usually connected to loose coupling
patterns. Patterns look like too tightly coupled after such thing
applied for my taste. The calling and binding of member function
pointers should be templatized to not confuse novices. Also i usually
suggest to consider boost::signals2 first when someone needs
multithreaded version of such.

observer only = great pattern to greatly simplify the architecture and
design (therefore the code as well)

observer + MVP = killer combo for GUIs
 
F

Francesco S. Carta

observer only = great pattern to greatly simplify the architecture and
design (therefore the code as well)

observer + MVP = killer combo for GUIs

uh... MVP stands for what? And with "killer" I suppose you mean that
that combo would be bad for GUIs, have I got it right?

I'd like to know the reason - not that it would mean much, before
knowing what MVP stands for, but you'll surely throw light on both.
 
V

Vladimir Jovic

Francesco said:
uh... MVP stands for what? And with "killer" I suppose you mean that
that combo would be bad for GUIs, have I got it right?

Sorry for not being clearer :(

That combination is superb for GUIs. All alternatives are weaker.

Next link might give you idea what the MVP is, but I do not really
recommend it.
http://en.wikipedia.org/wiki/Model-view-presenter
Little googling should give you better presentations, something like this :
http://en.wikipedia.org/wiki/Presenter_First
I'd like to know the reason - not that it would mean much, before
knowing what MVP stands for, but you'll surely throw light on both.

Google for the "observer pattern", and play a bit with boost::signals
(what oo tib recommended).
 
F

Francesco S. Carta

Sorry for not being clearer :(

That combination is superb for GUIs. All alternatives are weaker.

Ehehehe, "killer" is a double-edged (s)word ;-)
Next link might give you idea what the MVP is, but I do not really
recommend it.
http://en.wikipedia.org/wiki/Model-view-presenter

Heck, I tried "define:mvp" on google and got completely unrelated
results - I wondered if that meant "multi-visitor pattern" but of course
that was weird as an addition to "observer"... I didn't think about
looking up the acronym on wikipedia, I would have gotten there, somehow.
Little googling should give you better presentations, something like this :
http://en.wikipedia.org/wiki/Presenter_First


Google for the "observer pattern", and play a bit with boost::signals
(what oo tib recommended).

Thanks for the clarification and for the links, I'll have a look.
 

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

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top