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 ]