Topic: Member pointers: are they needed?


Author: "cjoy" <cjoy@houston.rr.com>
Date: Mon, 12 Feb 2001 19:06:08 GMT
Raw View
"Brian McNamara!" <gt5163b@prism.gatech.edu> wrote in message
news:95ppfp$m1l$1@news-int.gatech.edu...
> pdimov@techno-link.com once said:

<...snip..>
> (1) I suspect you can create a (set of) template(s) for the member
> functions, along the lines of
>
>    // untested code, just meant to illustrate the idea
>    template <class R, class X, class A, R (X::*mf)(A)>
>    struct MemFunToNormFun {
>       static R fun( X* x, A a ) { return x.*mf(a); }
>    };
>    // Then, using the example class above
>    int (*f)(X const&, long) =
>       &MemFunToNormFun<int,X const,long,&X::f>::fun
>    // You probably want to make many overloads of a function template
>    // which can deduce all the types and keep track of consts
>

In fact, there is already a library to treat member function pointers and
regular function pointers polymorphically in C++.  It is Rich Hickey's
callback library which can wrap either a member-function or function pointer
and treat both identically from a caller's perspective.  It can be found at
http://www.bestweb.net/~rhickey/index.html
One reason why you might not want to not treat the two interchangeably is
lifetime issues.  Regular function pointers don't have to worry about
lifetimes, pointers into objects do, if their parent object gets destroyed,
bad things will likely happen when you invoke that member function pointer.

CJ

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: bonnard@clipper.ens.fr (Valentin Bonnard)
Date: Wed, 7 Feb 2001 15:49:59 GMT
Raw View
pdimov@techno-link.com wrote:

> I think that member pointers do not need their own distinct types.

You may, in some cases, live as well using alternatives. That has
never been an argument against inclusion of a C++ feature.

> Given
>
> struct X
> {
>   int f(long) const;
>   int i;
> };
>
> &X::f may be represented as int (*) (X const &, long)

Yes, but it wouldn't work as well with a virtual function.

You can't pass your int (*) (X const&, long) to a function
that needs a int (*) (Y const&, long) (Y derived from X,
of course).

And it isn't Object Oriented, since it doesn't the dot
notation anymore to call a member function:

  X x;
  int (*ptr) (X const&, long) = &X::f;
  ptr (x, 3);

> and &X::i may be represented by int (*) (X &).

(I am sure you mean int& (*) (X &).)

Let's say we have

  int X::*ptr;
  ptr = &X::i;
  x.*ptr = 3;

You are replacing

  size_t ptr;
  ptr = offsetof (X, i);
  *((char*)&x + ptr) = 3;

with

int& some_unused_name (X & x)
{
  return x.i
}

  int& (*ptr) (X &);
  ptr = &some_unused_name;
  (*ptr) (x) = 3;

Both in term of time and space, which version is more
efficient ?

> Am I missing something? Do the dedicated member pointer types have
> greater expressive power?

Yes, you couldn't have polymorphism without them. (You could still
built some map<typeinfo, U T::* (V)>, but that would be at the same
time less efficient, more verbose, much more complicated, more
error-prone, and less flexible.)

--
Valentin Bonnard

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: pdimov@techno-link.com
Date: Wed, 7 Feb 2001 16:43:48 GMT
Raw View
In article <95ppfp$m1l$1@news-int.gatech.edu>,
  gt5163b@prism.gatech.edu (Brian McNamara!) wrote:
> pdimov@techno-link.com once said:
> >Am I missing something? Do the dedicated member pointer types have
> >greater expressive power?
>
> Despite what others in the thread have said, I think "no".  Except for
> the fact that your idea clashes with how C++ already works, I think
this
> would be a workable alternative.

[...]

> (2) I think your pointer-to-member-variable should be returning a
> reference, not a value (with the constness of the referrant being the
> same as the constness of the receiver object).

... and I don't see how to express this as a single function pointer.

--
Peter Dimov
Multi Media Ltd.


Sent via Deja.com
http://www.deja.com/

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: pdimov@techno-link.com
Date: Wed, 7 Feb 2001 17:11:03 GMT
Raw View
In article <95pek5$38t$02$1@news.t-online.com>,
  "Sebastian Moleski \(SurakWare\)" <smoleski@surakware.com> wrote:
> <pdimov@techno-link.com>:
> > Am I missing something? Do the dedicated member pointer types have
> > greater expressive power?
> Yes. Member function pointers still work polymorphically.

They'll still work polymorphically.

struct X
{
  virtual void f() = 0;
};

void __X_f(X & self) // compiler generated
{
  self.f();
}

&X::f would return &__X_f.

--
Peter Dimov
Multi Media Ltd.


Sent via Deja.com
http://www.deja.com/

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: pdimov@techno-link.com
Date: Wed, 7 Feb 2001 17:11:24 GMT
Raw View
In article <3A8019A3.29BB5A2B@lucent.com>,
  Michiel Salters <salters@lucent.com> wrote:
> pdimov@techno-link.com wrote:
>
> > I think that member pointers do not need their own distinct types.
Given
>
> > struct X {
> >   int f(long) const;
> >   int i;
> > };
>
> > &X::f may be represented as int (*) (X const &, long), and &X::i
may be
> > represented by int (*) (X &).
>
> Ehh? Care to explain that? That looks like pointers to functions
> returning int and taking (X const& and long) or (X&), respectively.
> That is, do you want to propose that &X::i has pointer-to-function
> type? That could of course be done, at a (possible) cost. When you'd
> use &X::i, you'd use it as
>
> X x;
> int (*IofX) (X &) = &X::i;
> IofX(x)=5; // Set x.i to 5

Yes, this was what I had in mind. Typical usage would be

std::for_each(first, last, &X::f);

// call void X::f() for *i, i in [first, last)

or

std::transform(first, last, first2, &X::i);

// *first2 = first->i

> This would involve a function call to some intermediate function. This
> in general cannot be inlined if IofX is passed across translation
units.
> By passing it as &X::i, only the offset needs to be passed and no
> function call is needed.
>
> (Insert chanting: "We don't want no stinkin' overhead" :-)

Right. Efficiency. No overhead allowed in C++. Yes, that's what I'm
missing.

Hmm, what about just defining operator() for member pointers? Still
allows their use as function objects, minus the overhead.

--
Peter Dimov
Multi Media Ltd.


Sent via Deja.com
http://www.deja.com/

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: Wed, 7 Feb 2001 18:13:10 GMT
Raw View
bonnard@clipper.ens.fr (Valentin Bonnard) writes:

>pdimov@techno-link.com wrote:
>
>> I think that member pointers do not need their own distinct types.
>
>You may, in some cases, live as well using alternatives. That has
>never been an argument against inclusion of a C++ feature.

Sure it has.  Consider the textbook example of a proposed C++
feature, namely `inherited::'.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: Andre@incognito.com (Andre Kostur)
Date: Wed, 7 Feb 2001 20:53:52 GMT
Raw View
rado42@my-deja.com (rado42) wrote in <95p9hi$bbd$1@nnrp1.deja.com>:

>But I have another question: Are member pointers REALLY useful? Can
>anybody give and example in which the BEST solution is using member
>(particularly funciton) pointers?

I found them useful in the following situation:

Code:

/* there should be headers and stuff here....*/

class SomeClass
{
public:
     typedef void(SomeClass::* Pmem)(istream& istr, ostrstream& ostr);

     map<string, Pmem> commandMap;

     void DoSomething(istream& istr, ostrstream& ostr) {};
     void DoQuit(istream& istr, ostrstream& ostr) {};

     void DoCommand(map<string, Pmem> & cmdMap, istream & istr, ostrstream
& ostr);
};

void SomeClass::Init()
{
    commandMap.clear();
    commandMap.insert(make_pair(string("quit"), &SomeClass::DoQuit));
    commandMap.insert(make_pair(string("something"),
&SomeClass::DoSomething));
}

void SomeClass::DoCommand(map<string, Pmem> & cmdMap, istream& istr,
ostrstream& ostr)
{
   string tempStr;

   istr >> tempStr;

   if(istr)
   {
       std::transform(tempStr.begin(), tempStr.end(), tempStr.begin(),
                    tolower);

       map<string, Pmem>::iterator where = cmdMap.find(tempStr);

       if(where != cmdMap.end())
       {
           this->*(where->second)(istr, ostr);
       }
   }
}



The rest of the class is a whole bunch of other stuff, but the idea is
there.  Assume that you are getting commands from some input stream (the
istream in the code), and assume that all of the commands have some sort of
output streamed into a string (the strstream in the code).  By using
pointer to member functions, I can have a simple mapping of command strings
to the functions which implement those commands.  If I need to add a new
command for whatever reason, I only need to implement the function which
actually does the work, and do a push_back of the command name:function
name pair into the command map.  I don't have to touch the actual command
"parsing" code.   The other way I can think of doing it is a monster switch
statement (or really big if..then...else if...else if...else if...
construct, since we're working with strings...).

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: "Sebastian Moleski \(SurakWare\)" <smoleski@surakware.com>
Date: Wed, 7 Feb 2001 20:54:37 GMT
Raw View
<pdimov@techno-link.com>:
> > Yes. Member function pointers still work polymorphically.
>
> They'll still work polymorphically.
>
> struct X
> {
>   virtual void f() = 0;
> };
>
> void __X_f(X & self) // compiler generated
> {
>   self.f();
> }
>
> &X::f would return &__X_f.

To be honest, most compilers already do it that way.

sm


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: pdimov@techno-link.com
Date: Wed, 7 Feb 2001 20:54:50 GMT
Raw View
In article <95pm37$ogm$1@nnrp1.deja.com>,
  Jim Hyslop <jim.hyslop@leitch.com> wrote:
> In article <95p1n4$3md$1@nnrp1.deja.com>,
>   pdimov@techno-link.com wrote:
> > I think that member pointers do not need their own distinct types.
> >
> > Am I missing something?
> Yes.
>
> For member functions, there is the problem of the implicit 'this'
> pointer.
>
> int X::f(long) const;
>
> is *not* the same function as
>
> int f(const X&, long);
>
> or, more precisely, (since 'this' is a pointer not a reference)
>
> int f(X const *, long)

Yes, I know that it may or may not be the same. This is not important.
The compiler can take care of the difference (by creating a forwarding
function, for example, and returning its address instead) if necessary.

--
Peter Dimov
Multi Media Ltd.


Sent via Deja.com
http://www.deja.com/

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: qrczak@knm.org.pl (Marcin 'Qrczak' Kowalczyk)
Date: Mon, 12 Feb 2001 14:30:01 CST
Raw View
Mon, 12 Feb 2001 19:06:08 GMT, cjoy <cjoy@houston.rr.com> pisze:

> One reason why you might not want to not treat the two interchangeably
> is lifetime issues.  Regular function pointers don't have to worry about
> lifetimes, pointers into objects do, if their parent object gets destroyed,
> bad things will likely happen when you invoke that member function pointer.

A member function pointer is not associated with an object.

Unfortunately C++ does not support partial application.

--
 __("<  Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/
 \__/
  ^^                      SYGNATURA ZAST   PCZA
QRCZAK

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]