tags:

views:

276

answers:

2

Hi, I have a abstract base class A and a set of 10 derived classes. The infix operator is overloaded in all of the derived classes

class A{
 public:
    void printNode( std::ostream& os )
    {
           this->printNode_p();
    } 
  protected:
    virtual void printNode_p( std::ostream& os )
    {
           os << (*this);
    }
};

There is a container which stores the base class pointers. I want to use boost::bind function to call the overloaded infix operator in each of its derived class. I have written like this

std::vector<A*> m_args
....
std::ostream os;
for_each( m_args.begin(), m_args.end(), bind(&A::printNode, _1, os) );

What is the problem with this code? In visual studio i am getting an error like this

error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access private member declared in class 'std::basic_ios<_Elem,_Traits>'

Thanks, Gokul.

+4  A: 

Consider this, which works as expected:

#include <iostream>

struct base
{
    virtual ~base(void) {}

    virtual void print(std::ostream& pStream) = 0;
};

struct foo : base
{
    void print(std::ostream& pStream) { pStream << "foo" << std::endl; }
};

struct bar : base
{
    void print(std::ostream& pStream) { pStream << "bar" << std::endl; }
};

#include <boost/bind.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <algorithm>

int main(void)
{
    boost::ptr_vector<base> v;
    v.push_back(new foo);
    v.push_back(new bar);

    std::for_each(v.begin(), v.end(),
                  boost::bind(&base::print, _1, boost::ref(std::cout)));
}

First off, since you're using boost you may as well use ptr_vector to handle memory management for you. So, that's in there.

Secondly, your error is because streams are not copyable; however, boost::bind will make a copy of all it's arguments when constructing the functor. Wrap it in a boost::reference_wrapper (using the boost::ref utility function), which is copyable. When the time comes, the wrapper will convert to the necessary type and you won't notice the difference.

(This is one of the situations boost::ref was made for.)


That all said, consider using BOOST_FOREACH, which in my opinion generates the cleanest code:

#include <boost/foreach.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <algorithm>

#define foreach BOOST_FOREACH

int main(void)
{
    boost::ptr_vector<base> v;
    v.push_back(new foo);
    v.push_back(new bar);

    foreach (base* b, v)
    {
        v->print(std::cout);
    }
}
GMan
Thanks.... i will look into boost::ptr_vector
Gokul
A: 

The problem was that std::ostream is not copyable. I fixed it like this

for_each( m_args.begin(), m_args.end(), bind(&A::printNode, _1, boost::ref(os) ) );

Thanks, Gokul.

Gokul