Boost function and bind issue

C

Chris Ahlstrom

This code compiles:

boost::asio::ip::tcp::acceptor m_acceptor; // declared in a class

connector::pointer new_conn(new connector(m_acceptor.io_service()));
m_acceptor.async_accept
(
new_conn->socket(),
boost::bind
(
&timingserver::handle_accept,
this,
boost::asio::placeholders::error,
new_conn
)
);

So now I want to pull out the boost::bind part and make a function object of it.

boost::function
<
void
(
const boost::system::error_code &,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator
)
> b = boost::bind
(
&timingserver::handle_accept,
this,
boost::asio::placeholders::error,
new_conn
);
m_acceptor.async_accept(new_conn->socket(), b);

The ultimate error I get is

/usr/include/boost/asio/detail/bind_handler.hpp:39: error: no match for call to

'(
boost::function
<
void
(
const boost::system::error_code&,
boost::asio::ip::basic_resolver_iterator said:
) (boost::system::error_code&)'

/usr/include/boost/function/function_template.hpp:1006: note: candidates are:

R boost::function2<R, T1, T2>::eek:perator()(T0, T1) const

[with R = void,
T0 = const boost::system::error_code&,
T1 = boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp>]

I've been able to make similar function objects from other bound functions,
so I'm a bit puzzled here.
 
F

Francesco S. Carta

This code compiles:

Uhm, no, as it is, it doesn't ;-)

Please see FAQ 5.8 and post complete code.
boost::asio::ip::tcp::acceptor m_acceptor; // declared in a class

connector::pointer new_conn(new connector(m_acceptor.io_service()));
m_acceptor.async_accept
(
new_conn->socket(),
boost::bind
(
&timingserver::handle_accept,
this,
boost::asio::placeholders::error,
new_conn
)
);

So now I want to pull out the boost::bind part and make a function object of it.

boost::function
<
void
(
const boost::system::error_code&,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator
)
b = boost::bind
(
&timingserver::handle_accept,
this,
boost::asio::placeholders::error,
new_conn
);
m_acceptor.async_accept(new_conn->socket(), b);

The ultimate error I get is

/usr/include/boost/asio/detail/bind_handler.hpp:39: error: no match for call to

'(
boost::function
<
void
(
const boost::system::error_code&,
boost::asio::ip::basic_resolver_iterator said:
) (boost::system::error_code&)'

/usr/include/boost/function/function_template.hpp:1006: note: candidates are:

R boost::function2<R, T1, T2>::eek:perator()(T0, T1) const

[with R = void,
T0 = const boost::system::error_code&,
T1 = boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp>]

I've been able to make similar function objects from other bound functions,
so I'm a bit puzzled here.

Don't know, I would try to solve it for you but I've not enough time to
make something compilable out of your code.

Post a complete misbehaving example and we will try to help you - by the
way, there are boost mailing lists and groups out there, just to let you
know; you will get help here eventually but you should ease our
reviewing task a bit.
 
C

Chris Ahlstrom

Francesco S. Carta posted this message in ROT13 encoding:
Uhm, no, as it is, it doesn't ;-)

Please see FAQ 5.8 and post complete code.

Actually, I'm hopeful that this problem is easier resolved by inspection
from someone who's been through the issue before.

Why does the passing of the bind object directly to async_accept() compile
fine, while making a real object out of it, using boost::function, and
passing that, not work.

Hmmmm. I'm thinking now I may know why. A misapprehension ... My
boost::function call isn't creating a function object compatible with
async_write(). The other ones I got work were passed to functions that
I wrote, and so could control the function signature.

But I've got to go play some soccer first. My brain will probably work
better afterwards anyway.
Don't know, I would try to solve it for you but I've not enough time to
make something compilable out of your code.

Oh, I understand. I only post questions when I'm stumped, and think the
answer would be obvious to somebody else.
Post a complete misbehaving example and we will try to help you - by the
way, there are boost mailing lists and groups out there, just to let you
know; you will get help here eventually but you should ease our
reviewing task a bit.

I can't find any *boost* (regexp) newsgroups in Usenet. I'm not a big fan
of visiting fora and wikis through my browser.

Thanks for responding! If I figure it out, I'll at least post the answer
here.
 
F

Francesco S. Carta

Francesco S. Carta posted this message in ROT13 encoding:


Actually, I'm hopeful that this problem is easier resolved by inspection
from someone who's been through the issue before.

As you prefer, but by not following the guidelines you're actively
narrowing down the frame of potential responses. Furthermore, you're
surely not a newbie, so you might take the chance to "act as expected"
when you happen to ask for help - showing thus an example of "good
asking style".

As you can see you did not get any valuable reply yet: consider that
somebody could well know what you're after and could deliberately omit
to post a reply just because you didn't follow the mentioned guidelines.
(!!!)
Why does the passing of the bind object directly to async_accept() compile
fine, while making a real object out of it, using boost::function, and
passing that, not work.

Hmmmm. I'm thinking now I may know why. A misapprehension ... My
boost::function call isn't creating a function object compatible with
async_write(). The other ones I got work were passed to functions that
I wrote, and so could control the function signature.

But I've got to go play some soccer first. My brain will probably work
better afterwards anyway.


Oh, I understand. I only post questions when I'm stumped, and think the
answer would be obvious to somebody else.

Sure, but maybe somebody less experienced and willing to investigate
(just like me) would have taken advantage of feeding your code to a
compiler and fiddling with it ;-)
I can't find any *boost* (regexp) newsgroups in Usenet. I'm not a big fan
of visiting fora and wikis through my browser.

Mailing lists aren't all that different from Usenet groups... maybe that
would pollute your inbox for some time before you get a meaningful reply
and decide to stop reading the list, but that would be a minor problem,
easily solvable.
Thanks for responding! If I figure it out, I'll at least post the answer
here.

Well, for what is worth, you're welcome!
I look forward to see the solution to this issue.
 
C

Chris Ahlstrom

Francesco S. Carta posted this message in ROT13 encoding:
Well, for what is worth, you're welcome!
I look forward to see the solution to this issue.

I'm more confused than ever, as I see that the Boost sockets'
async_accept()'s second parameter is a templated type. So I should be
able to directly pass a boost::function-wrapped object to async_write().

Neither the soccer nor a night's rest is doing the trick.
 
F

Francesco S. Carta

Francesco S. Carta posted this message in ROT13 encoding:


I'm more confused than ever, as I see that the Boost sockets'
async_accept()'s second parameter is a templated type. So I should be
able to directly pass a boost::function-wrapped object to async_write().

Neither the soccer nor a night's rest is doing the trick.

Several walkable paths:

- go on waiting for someone to drop the solution here on the base of the
info you provided thus far;

- post here some complete minimal misbehaving program to let people
fiddle with it - as you should know, cutting down your program could
actually bring you to the solution - if that doesn't work, you'll have
the minimal program ready to be posted here;

- bring your issue to one of the mailing lists available here:
http://www.boost.org/community/groups.html

(I must also point out that you didn't mention which compiler is
refusing your code)
 
M

Michael Doubez

So now I want to pull out the boost::bind part and make a function object of it.

   boost::function
   <
      void
      (
         const boost::system::error_code &,
         boost::asio::ip::tcp::resolver::iterator endpoint_iterator
      )
   > b = boost::bind
   (
      &timingserver::handle_accept,
      this,
      boost::asio::placeholders::error,
      new_conn
   );
   m_acceptor.async_accept(new_conn->socket(), b);

The ultimate error I get is

/usr/include/boost/asio/detail/bind_handler.hpp:39: error: no match for call to

 '(
      boost::function
      <
         void
         (
            const boost::system::error_code&,
             boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp>
         )
      >i
   ) (boost::system::error_code&)'

/usr/include/boost/function/function_template.hpp:1006: note: candidates are:

   R boost::function2<R, T1, T2>::eek:perator()(T0, T1) const

 [with R = void,
       T0 = const boost::system::error_code&,
       T1 = boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp>]

I've been able to make similar function objects from other bound functions,
so I'm a bit puzzled here.

*According to documentation*, async_accept takes as parameter a
AcceptHandler:
"An accept handler must meet the requirements for a handler. A value h
of an accept handler class should work correctly in the expression
h(ec), where ec is an lvalue of type const error_code."

With Boost.Function, the type should be:
boost::function1<void,boost::system::error_code>
or as you put it:
boost::function<void(const boost::system::error_code&)>

RTFM. Really do it.
 
C

Chris Ahlstrom

Michael Doubez posted this message in ROT13 encoding:
*According to documentation*, async_accept takes as parameter a
AcceptHandler:
"An accept handler must meet the requirements for a handler. A value h
of an accept handler class should work correctly in the expression
h(ec), where ec is an lvalue of type const error_code."

With Boost.Function, the type should be:
boost::function1<void,boost::system::error_code>
or as you put it:
boost::function<void(const boost::system::error_code&)>

RTFM. Really do it.

Thanks. But what I really wanted to do was (1) bind a class member function
into a function that met those requirements, and (2) save the bound function
for later invocation inside async_write().

The first was easy, even with extra arguments; the second I'm having trouble
with.
 
C

Chris Ahlstrom

Chris Ahlstrom posted this message in ROT13 encoding:
Michael Doubez posted this message in ROT13 encoding:

That's the "portable" version, for backward compilers.

That's the normal version.
Thanks. But what I really wanted to do was (1) bind a class member function
into a function that met those requirements, and (2) save the bound function
for later invocation inside async_write().

Finally got it to compile. The original version (actually based on
boost/asio/examples/serialization/server.cpp) that was easy was:

connector::pointer new_conn(new connector(m_acceptor.io_service()));

m_acceptor.async_accept
(
new_conn->socket(),
boost::bind
(
&timingserver::handle_accept,
this,
boost::asio::placeholders::error,
new_conn
)
);

This storage of the bound function compiles:

boost::function<void(const boost::system::error_code & e)> b =
boost::bind
(
&timingserver::handle_accept,
this,
boost::asio::placeholders::error,
new_conn
);
m_acceptor.async_accept
(
new_conn->socket(),
b
);

This is with g++ (Debian 4.4.4-8) 4.4.5 20100728 (prerelease).
Hope it actually runs. I don't get why it works. :-(

Thanks for all the advice. It actually helped!
 
M

Michael Doubez

Chris Ahlstrom posted this message in ROT13 encoding:


That's the "portable" version, for backward compilers.


That's the normal version.


Finally got it to compile.  The original version (actually based on
boost/asio/examples/serialization/server.cpp) that was easy was:

   connector::pointer new_conn(new connector(m_acceptor.io_service()));

   m_acceptor.async_accept
   (
      new_conn->socket(),
      boost::bind
      (
         &timingserver::handle_accept,
         this,
         boost::asio::placeholders::error,
         new_conn
      )
   );

This storage of the bound function compiles:

   boost::function<void(const boost::system::error_code & e)> b =
      boost::bind
      (
         &timingserver::handle_accept,
         this,
         boost::asio::placeholders::error,
         new_conn
      );
   m_acceptor.async_accept
   (
      new_conn->socket(),
      b
   );

This is with g++ (Debian 4.4.4-8) 4.4.5 20100728 (prerelease).
Hope it actually runs.  I don't get why it works.  :-(

What works ? The change ?

Truly, there is not much to understand: async_accept expects a functor
that takes one parameter (a boost::system::error_code). This is what
bind() provides; in your example it instantiate a boost::function that
calls this->handle_accept( _ , new_conn) where _ is the placeholder
for the future boost::system::error_code parameter.

If you want to store it, you have to know the type of the variable
that will store it (unless you use C++0x's auto); the relevant type is
boost::function<void(const boost::system::error_code&)>.
 
C

Chris Ahlstrom

Michael Doubez posted this message in ROT13 encoding:
What works ? The change ?

Truly, there is not much to understand...

You seem to be a knowledgeable fellow.
So perhaps you can tell me how the boost::function object
get the correct parameter to the actual call that async_write() makes.
: async_accept expects a functor
that takes one parameter (a boost::system::error_code). This is what
bind() provides; in your example it instantiate a boost::function that
calls this->handle_accept( _ , new_conn) where _ is the placeholder
for the future boost::system::error_code parameter.

But how does the correct parameter get substituted? I found that
other template parameters for boost::function also compiled correctly,
though the result was unsuitable for async_write().

<repetition snipped>
 
C

Chris Ahlstrom

Michael Doubez posted this message in ROT13 encoding:
Yes but a complete explanation is an awful lot of template :)

Basically, boost::functionN<R,P1,2,...,PN> stores a pointer to an
interface defining a virtual R fN(P1,P2...) - this is type erasure.

The problem is then to instantiate the correct function object which
is done with templated constructors and more generaly boost::bind().
The generated object/class are on the model of good old
std::mem_fun(), std::bind1st() ...

It is easier with boost:bind() placeholder: _1, _2 ....
The parameter your pass are stores in the function object and the _1,
_2, _N placeholder determines which class must be instantiated:
instantiated with _1, the first parameter passed to the interface is
used, and so on.

There may be some element in:"C++ Template Metaprogramming: Concepts,
Tools, and Techniques from Boost and Beyond"
I don't remember.

Thanks!

I bought a copy of "Beyond the C++ Standard Library: An Introduction to
Boost", quite awhile back, and it is a great resource to start with, opened
my eyes quite a bit, but it is still only an introduction, and the examples
are a bit too simple.

So I really appreciate your help.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top