Boost logo

Boost :

From: Matthew D. Langston (langston_at_[hidden])
Date: 1999-11-01 20:09:51


Hi John,

The problem is due to the fact that there is no conversion from
"shared_ptr<Base>" to "Base*". Why is this conversion trying to take
place? To see why, let's look back at your call to "for_each":

  std::for_each(x.begin(), x.end(), std::mem_fun(&Base::print));

The "mem_fun" helper function is returning an object (a
"mem_fun_t<void,Base>" in this case) whose "operator ()" takes a "Base*"
as an argument. However, the call to "for_each" is passing a
"shared_ptr<Base>" element to "operator ()" on each iteration, and there
is no conversion from "shared_ptr<Base>" to "Base*".

The right way to do what you want to do is to have a complimentary set
of "mem_fun_*" objects whose "operator ()" takes a "shared_ptr<T>"
instead of a "T*". I have designed a small extension to the boost
library which does just this, and I have attached it to this e-mail as
the file "functional_boost.hxx". Note that my "mem_fun_*" objects are
not specific to boost - they should work with *all* smart pointers (that
was the goal of my design anyway).

Please note that I have heretofore not submitted this work to the boost
developers because I am not sure if I am happy with my design. However,
my "boost extension" library does work (I use it in my projects), and so
it is probably mature enough for a general discussion on the boost list
if there is interest. If it is not my current design, or some version
thereof, then we (the "boost users and developers") need to design such
an extension to the boost library because this style of problem crops up
all of the time (at least in my work, and for those people I help).

Another reason I have heretofore not submitted my "boost extension"
library is because I have not documented it (other than the comments in
the code). With these caveats, perhaps you will find my attachment
useful. FYI, my "boost extension" library is currently in the namespace
MDL, not "boost". Here is how you would use it in your case:

  std::for_each(x.begin(), x.end(), MDL::mem_fun_ptr(&Base::print, boost::shared_ptr<Base>()));

I have changed the example code that you originally sent in to use
"MDL::mem_fun_ptr" - it is also attached to this e-mail as the file
"mem_fun_ptr.cxx". I tested it using gcc 2.95.2 under RedHat Linux 6.1
Intel.

--
Matthew D. Langston
SLD, Stanford Linear Accelerator Center
langston_at_[hidden]
John Hunter wrote:
> 
> I have a piece of sample code in which I have a vector of shared
> pointers (boost::shared_ptr<>).  Can anyone tell me why I am unable to
> iterate using the STL algorithm for_each (fail to compile; message
> below) but I can manually loop over the container just fine.
> 
> e.g.
>   //this works
>   vector<Aptr>::iterator ix;
>   for (ix = x.begin(); ix != x.end(); ++ix)
>     (*ix)->print();
> 
>   //this doesn't
>   std::for_each(x.begin(), x.end(), std::mem_fun(&Base::print));
> 
> Thanks in advace; complete code and compiler error message below.
> 
> John Hunter
> 
> Code:
> #include <iostream>
> #include <string>
> #include <map>
> #include <memory>
> #include <vector>
> #include <algorithm>
> #include <boost/smart_ptr.hpp>
> 
> class Base {
> public:
>   virtual ~Base() {};
>   virtual void print() = 0;
>   virtual Base* clone() const { } ;
> };
> 
> class Foo : public Base {
>   int x;
> public:
>   Foo() : x(0) {};
>   ~Foo () { std::cout << "Foo: ouch" << endl; }
>   void print() { std::cout << "I am Foo" << endl;}
>   Foo* clone() const { return new Foo(*this); }
> };
> 
> class Bar : public Base {
>   int x;
> public:
>   Bar() : x(0) {};
>   ~Bar () { std::cout << "Bar: ouch" << endl; }
>   void print() { std::cout << "I am Bar" << endl;}
>   Bar* clone() const { return new Bar(*this); }
> };
> 
> int main() {
> 
>   const Foo foo;
>   const Bar bar;
> 
>   typedef std::map<const std::string, const Base*> Map;
>   Map m;
>   m["foo"] = &foo;
>   m["bar"] = &bar;
> 
>   typedef boost::shared_ptr<Base> Aptr;
>   vector<Aptr> x;
> 
>   std::string s;
>   std::cout << "enter foo or bar" << endl;
>   while (cin >> s)
>     x.push_back(Aptr(m[s]->clone())); //use the constructor
> 
>   //this works
>   vector<Aptr>::iterator ix;
>   for (ix = x.begin(); ix != x.end(); ++ix)
>     (*ix)->print();
> 
>   //this doesn't
>   std::for_each(x.begin(), x.end(), std::mem_fun(&Base::print));
> }
> 
> Compiler error message:
> localhost:~/c/examples> g++ test.cpp
> g++ test.cpp
> 
> /usr/local/lib/gcc-lib/i586-pc-linux-gnu/2.95/../../../../include/g++-3/stl_algo.h:
> In function `class mem_fun_t<void,Base> for_each<main()::Aptr *,
> mem_fun_t<void,Base> >(main()::Aptr *, main()::Aptr *,
> mem_fun_t<void,Base>)':
> test.cpp:58:   instantiated from here
> /usr/local/lib/gcc-lib/i586-pc-linux-gnu/2.95/../../../../include/g++-3/stl_algo.h:83:
> no match for call to `(mem_fun_t<void,Base>) (boost::shared_ptr<Base>
> &)'
> /usr/local/lib/gcc-lib/i586-pc-linux-gnu/2.95/../../../../include/g++-3/stl_function.h:566:
> candidates are: void mem_fun_t<void,Base>::operator ()(Base *) const
> localhost:~/c/examples>

#ifndef MDL_FUNCTIONAL
#define MDL_FUNCTIONAL

// Copyright (C) 1999 Matthew D. Langston <langston_at_[hidden]>
//
// This file is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at
// your option) any later version.
//
// This file is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this file; if not, write to:
//
// Free Software Foundation, Inc.
// Suite 330
// 59 Temple Place
// Boston, MA 02111-1307, USA.

// This is a collection of extensions I have written to the C++ standard
// library. Each logical component is described below.

#include <functional>

namespace MDL
{
   // These are the familiar member function adaptors from the C++
   // standard library that have been extended, in a backward compatible
   // way, so that the pointer type used to call back on the member
   // function pointer is parameterized. This allows user defined
   // pointer types (e.g. "smart pointers") to be used in addition to
   // the built-in pointer types.
   //
   // This is achieved by adding a third template parameter to the
   // "mem_fun_t", "const_mem_fun_t", "mem_fun1_t" and
   // "const_mem_fun1_t" member function adaptors. The default type for
   // this new third template parameter is whatever the type of
   // "iterator_traits<_Tp>::pointer" is, where "_Tp" is the second
   // template parameter in the classes below. Thus, the interface and
   // behavior of these new member function adaptors is identical to
   // their counterparts in the C++ standard library, and can be used as
   // drop-in replacements for them.
   //
   // There are also four new helper functions, each with the same name
   // "mem_fun_ptr", which are overloaded to makes it easier to create
   // these enhanced function adapters. Use them in the same spirit as
   // the "mem_fun" and "mem_fun_ref" helper functions from the C++
   // standard library.

   template <class _Ret, class _Tp, class _Ptr = _Tp*>
      class mem_fun_t : public unary_function<_Ptr,_Ret> {
         public:
            explicit mem_fun_t(result_type (_Tp::*__pf)()) : _M_f(__pf) {}
            result_type operator()(argument_type __p) const { return (*__p.*_M_f)(); }
         private:
            result_type (_Tp::*_M_f)();
      };

   template <class _Ret, class _Tp, class _Ptr = const _Tp*>
      class const_mem_fun_t : public unary_function<_Ptr,_Ret> {
         public:
            explicit const_mem_fun_t(result_type (_Tp::*__pf)() const) : _M_f(__pf) {}
            result_type operator()(argument_type __p) const { return (*__p.*_M_f)(); }
         private:
            result_type (_Tp::*_M_f)() const;
      };

   template <class _Ret, class _Tp, class _Arg, class _Ptr = _Tp*>
      class mem_fun1_t : public binary_function<_Ptr,_Arg,_Ret> {
         public:
            explicit mem_fun1_t(result_type (_Tp::*__pf)(_Arg)) : _M_f(__pf) {}
            result_type operator()(first_argument_type __p, _Arg __x) const { return (*__p.*_M_f)(__x); }
         private:
            result_type (_Tp::*_M_f)(_Arg);
      };

   template <class _Ret, class _Tp, class _Arg, class _Ptr = const _Tp*>
      class const_mem_fun1_t : public binary_function<_Ptr,_Arg,_Ret> {
         public:
            explicit const_mem_fun1_t(result_type (_Tp::*__pf)(_Arg) const) : _M_f(__pf) {}
            result_type operator()(first_argument_type __p, _Arg __x) const
            { return (*__p.*_M_f)(__x); }
         private:
            result_type (_Tp::*_M_f)(_Arg) const;
      };

   // Adaptor helper functions. There is only one: mem_fun_ptr.

   template <class _Ret, class _Tp, class _Ptr>
      inline mem_fun_t<_Ret,_Tp,_Ptr> mem_fun_ptr(_Ret (_Tp::*__f)(), _Ptr __ptr)
      { return mem_fun_t<_Ret,_Tp,_Ptr>(__f); }

   template <class _Ret, class _Tp, class _Ptr>
      inline const_mem_fun_t<_Ret,_Tp,_Ptr> mem_fun_ptr(_Ret (_Tp::*__f)() const, _Ptr __ptr)
      { return const_mem_fun_t<_Ret,_Tp,_Ptr>(__f); }

   template <class _Ret, class _Tp, class _Arg, class _Ptr>
      inline mem_fun1_t<_Ret,_Tp,_Arg,_Ptr> mem_fun_ptr(_Ret (_Tp::*__f)(_Arg), _Ptr __ptr)
      { return mem_fun1_t<_Ret,_Tp,_Arg,_Ptr>(__f); }

   template <class _Ret, class _Tp, class _Arg, class _Ptr>
      inline const_mem_fun1_t<_Ret,_Tp,_Arg,_Ptr> mem_fun_ptr(_Ret (_Tp::*__f)(_Arg) const, _Ptr __ptr)
      { return const_mem_fun1_t<_Ret,_Tp,_Arg,_Ptr>(__f); }
}

#endif // MDL_FUNCTIONAL


#include <iostream>
#include <string>
#include <map>
#include <memory>
#include <vector>
#include <algorithm>
#include <boost/smart_ptr.hpp>
#include "functional_boost.hxx"

class Base {
public:
  virtual ~Base() {};
  virtual void print() = 0;
  virtual Base* clone() const { } ;
};

class Foo : public Base {
  int x;
public:
  Foo() : x(0) {};
  ~Foo () { std::cout << "Foo: ouch" << endl; }
  void print() { std::cout << "I am Foo" << endl;}
  Foo* clone() const { return new Foo(*this); }
};

class Bar : public Base {
  int x;
public:
  Bar() : x(0) {};
  ~Bar () { std::cout << "Bar: ouch" << endl; }
  void print() { std::cout << "I am Bar" << endl;}
  Bar* clone() const { return new Bar(*this); }
};

int main() {

  const Foo foo;
  const Bar bar;

  typedef std::map<const std::string, const Base*> Map;
  Map m;
  m["foo"] = &foo;
  m["bar"] = &bar;

  typedef boost::shared_ptr<Base> Aptr;
  vector<Aptr> x;

  std::string s;
  std::cout << "enter foo or bar" << endl;
  while (cin >> s)
    x.push_back(Aptr(m[s]->clone())); //use the constructor

  //this works
  vector<Aptr>::iterator ix;
  for (ix = x.begin(); ix != x.end(); ++ix)
    (*ix)->print();
  
  std::for_each(x.begin(), x.end(), MDL::mem_fun_ptr(&Base::print, boost::shared_ptr<Base>()));
}

// Local variables:
// compile-command: "/usr/local/bin/g++ -Wall -I/mnt/hdc/projects/c++/boost mem_fun_ptr.cxx -o mem_fun_ptr"
// End:


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk