4
m_io_service.post(boost::ref(i));

I have this call in a section of code, the underlying type i is definetly a callable (because removing the boost::ref leads to pass by value, which works fine), however clang tells me that :

/opt/dev_64_swat/proto-rpc2/dependencies/boost/include/boost/asio/handler_invoke_hook.hpp:64:3: error: type 'boost::reference_wrapper<rubble::rpc::TcpFrontEndConnectionInvoker>' does not provide a call operator

How do I pass by reference, I have objects that outlive the asynchronous calls, and they would be more elegant (less boost::shared_ptr<..> 's as members) if I could pass them by reference.

-- edit --

I have grepped through the example directory of asio, and boost::ref is not demonstrated for completion handlers. So I guess I am out of luck here. Is there a reason why the handlers don't have version accepting ref's ?

-- edit 2 : what I Looks like(don't bother looking at this unless you are suspicious of the implementation). --

namespace rubble { namespace rpc {
  struct InProcessInvoker : public InvokerBase
  {
    struct notification_object_
    {
      typedef notification_object_ * ptr;

      notification_object_()
      {
        reset();
      }
      void reset()
      {
        ready = false;
      }
      bool ready;
      boost::mutex mutex;
      boost::condition_variable cond;
    };

    InProcessInvoker(BackEnd & b_in)
      : b(b_in),
        notification_object(new notification_object_())
    {
      b.connect(m_client_data);
    }

    ~InProcessInvoker()
    {
      if( m_client_data.unique() )
      {
        b.disconect(m_client_data);
        delete notification_object;
      }
    }

    bool is_useable()
    {
      return b.is_useable();
    }

    void reset()
    {
      notification_object->reset();
      m_client_data->request().Clear();
      m_client_data->response().Clear();
      m_client_data->error_code().clear();
      BOOST_ASSERT_MSG( m_client_data->is_rpc_active() == false,
        "THE FLAG THAT REPRESENTS ACTIVE "
        "RPC SHOULD NOT BE SET WHEN RESETING AN OBJECT FOR RPC");
    }

    void invoke()
    {
      b.invoke(*this);
    }

    void operator() ()
    {
      service->dispatch(*client_cookie,*m_client_data);
      b.end_rpc(m_client_data.get());

      boost::lock_guard<boost::mutex> lock(notification_object->mutex);
      notification_object->ready=true;
      notification_object->cond.notify_one();
    }

    void after_post()
    {
      boost::unique_lock<boost::mutex> lock(notification_object->mutex);
      if(!notification_object->ready)
        notification_object->cond.wait(lock);
    }

    notification_object_::ptr notification_object;
    BackEnd & b;
  };

} }
Hassan Syed
  • 20,075
  • 11
  • 87
  • 171

2 Answers2

6

boost::ref doesn't provide an overload of operator(). Hence, the return cannot be used directly as a callback. There are 2 options:

  1. C++03: Use boost::bind to wrap the ref, and it will do what you want

    m_io_service.post(boost::bind<ReturnType>(boost::ref(i)))

    Note that you have to specify the return type unless the original functor i has a typedef for result_type

  2. C++11: Use std::ref instead, which does provide an operator() which passes through to the contained reference

    m_io_service.post(std::ref(i))

murrekatt
  • 5,961
  • 5
  • 39
  • 63
Dave S
  • 20,507
  • 3
  • 48
  • 68
  • This is correct. `boost::ref` doesn't provide `operator()`, which is what the error message says. `asio::post` needs a handler (function) to call. – murrekatt Sep 02 '11 at 12:03
  • yes, however would it not have been prudent for the library implementer to provide an overload (for the async dispatch calls) for the template `boost::reference_wrapper` ? in order to compensate for the missing call operator, just curious about it. I'll probably go for `std::ref`:D thanks. – Hassan Syed Sep 02 '11 at 12:08
  • 1
    Well, the problem is every library writer that accepts functors would have to add the `boost::reference_wrapper` overload (which is what `bind` does) to their possible set of functors. Since ASIO can be found in non-boost flavor, adding extra overloads for boost specific wrappers seems to be the wrong approach. On the other hand, making the users of `boost::ref` use `boost::bind` is less work for the library developers, so they went that approach. – Dave S Sep 02 '11 at 12:10
  • boost::bind seems the cleanest way for portability. std::ref is still in limbo till the libraries are finalized. – Hassan Syed Sep 02 '11 at 12:44
2

Seems boost::ref is not intended for such usage. boost::ref provides wrapper so it's questionable what would be more effective, to pass by value or by boost::ref, mostly depends on your callable object copy constructor. As a workaround you can use boost::bind:

m_io_service.post(boost::bind(&Callable::operator(), &i));
Andriy Tylychko
  • 15,967
  • 6
  • 64
  • 112