Topic: mem_fun questions


Author: Dave Sugar <dsugar@dolphinsoft.com>
Date: 1999/05/10
Raw View
  I have been working with for_each and using member functions and can't
quite get it to work everywhere.  Here is what I have.

class XPtr
{
    public:
        XPtr (X *i_pX) m_pX (i_pX) { m_pX->incRef (); };
        ~XPtr () { if (m_pX->decRef () < 1) delete m_pX; };

        ostream *put (ostream *o_stream) const
                { return (m_pX->put (*o_stream); };

        X *operator () (void) { return (m_pX); };

    private:
        X    *m_pX;
};

class X : public vector <XPtr>
{
    public:
        void push_back (const XPtr &i_X);            // custom push_back
and insert which do stuff after inserting items
        void insert (iterator pos, XPtr &i_X);

          virtual ostream &put (ostream &i_nStream) const;

    protected:
        friend class XPtr;
        unsigned short   getRefCount (void) { return (m_nRefCount); };
        unsigned short   incRef (void) { return (++m_nRefCount); };
        unsigned short   decRef (void) { return (--m_nRefCount); };

        unsigned short   m_nRefCount;
};



now my X::put function is defined like this:

ostream &X::put (ostream &i_nStream) const
{
    for_each (begin (), end (), bind2nd (mem_fun_ref (&XPtr::put),
&i_nStream));
    return (i_nStream);
}

and this compiles on my compiler (Metrowerks CodeWarrior Pro 4 on Mac).
But I get a warning stating:
Warning: illegal const/volatile '&' reference initialization
when it is instantiating the binder2nd template.

This is as good as I could get it.  From what I understand from reading
this is the way to do it.  I really wanted to have the XPtr::put () take
an ostream & instead of an ostream *, but that doesn't work at all.
Anybody know why??  Should it work with references also?

Is this code correct, is there a better way.  Before I created a
function-object to deal with this case, but I perfer use the mem_fun
stuff instead of having a whole seperate class just to output stuff.
And there will be other thing I need to do with like this, which I would
prefer to do with member functions.

Anyway, I went to go compile this code on a UNIX box, with g++ (version
2.8.1) and it totally barfed at this put function and I have no idea how
to make it work.

g++'s complaints are as follows:
 In method `class ostream & X::put(class ostream &) const':
no matching function for call to `mem_fun_ref (ostream *
(XPtr::*)(ostream *) const)'

And the function does exist.
I'm pretty sure that 2.8.1 is the latest version of g++ and I have
included <functional> and it seems pretty happy.

any ideas?
Thanks
Dave Sugar
dsugar@dolphinsoft.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: sbnaran@localhost.localdomain.COM (Siemel Naran)
Date: 1999/05/10
Raw View
On 10 May 99 12:49:07 GMT, Dave Sugar <dsugar@dolphinsoft.com> wrote:

>        ostream *put (ostream *o_stream) const

>class X : public vector <XPtr>

>ostream &X::put (ostream &i_nStream) const
>{
>    for_each (begin (), end (), bind2nd (mem_fun_ref (&XPtr::put),
>&i_nStream));
>    return (i_nStream);
>}
>
>and this compiles on my compiler (Metrowerks CodeWarrior Pro 4 on Mac).
>But I get a warning stating:
>Warning: illegal const/volatile '&' reference initialization
>when it is instantiating the binder2nd template.

This code looks fine.  Como accepts it.  I'm using the new STL library
here, which has a proper <functional> header file.  (Except that ideally
it should not even have functions mem_fun1 and mem_fun1_ref.)

G++ gave me the strange error about no mem_fun_ref to call.  I replaced
"mem_fun_ref" with "mem_fun1_ref" and it worked.  BTW, the function
"mem_fun1_ref" used to be in the standard but no longer is, but many
libraries still have it.  (In the good old days, mem_fun_ref used to be
for member functions of zero arguments, and mem_fun1_ref for member
functions of one argument.  But in new times, mem_fun_ref is for both
classes of member functions.  Thanks to template argument deduction.)



>This is as good as I could get it.  From what I understand from reading
>this is the way to do it.  I really wanted to have the XPtr::put () take
>an ostream & instead of an ostream *, but that doesn't work at all.
>Anybody know why??  Should it work with references also?

Suppose you had
         void put (ostream& o_stream) const;

The reason has to do with references to references.  The function object
returned by std::mem_fun_ref (&XPtr::put) is
   a binary function object
   actual type std::mem_fun1_ref_t<void,Xptr,istream&>
   first_argument_type == Xptr const & // as the member function is const
   second_argument_type == ostream&

The function object returned by std::bind2nd(...,i_nStream) is
   a unary function object
   actual type std::binder2nd<Oper> // Oper same as the object above
   bound_argument_type == Oper::second_argument_type == ostream&

The constructor of class binder2nd is actually
   binder2nd(const Oper&, typename Oper::second_argument_type const &);
In our case this is
   binder2nd(const Oper&, istream & const &);

Qualifying a reference as const (the first 'const') is useless.
A reference to a reference is illegal in current C++.


Solutions:

1. Change C++ so that a reference to a reference means a reference,
   at least for implicit instantiations.

2. Change C++ so that constructor of binder2nd is
      binder2nd(const Oper&, typename Oper::second_argument_type);
   This may involve changing the derivation of std::plus and so on
   so that the argument of operator() matches the typedefs.

3. Leave C++ as is and make the user use proxy references.  Eg,
      template <class T> class Reference { T& ref; Reference(T&); }
      void Xptr::put (Reference<ostream>) const;
   We're now passing the reference by value!  The binder2nd ctor
      binder2nd(const Oper&, const Reference<istream>&);

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]