boost::asio::asyn_accept handler
I am looking at the example source at
http://www.boost.org/doc/libs/1_62_0/doc/html/boost_asio/tutorial/tutdaytime...
It passes their own connection class to the accept handler as an argument:
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
boost::asio::placeholders::error));
I tried to implement a class method that would do the same:
void ServerSocketASIO::Listen(boost::asio::ip::tcp::acceptor & acceptor,
std::function
On 28/03/2017 08:56, Christopher Pisz wrote:
I am looking at the example source at http://www.boost.org/doc/libs/1_62_0/doc/html/boost_asio/tutorial/tutdaytime...
It passes their own connection class to the accept handler as an argument:
acceptor_.async_accept(new_connection->socket(), boost::bind(&tcp_server::handle_accept, this, new_connection, boost::asio::placeholders::error));
I tried to implement a class method that would do the same:
void ServerSocketASIO::Listen(boost::asio::ip::tcp::acceptor & acceptor, std::function
callback) { acceptor.async_accept(m_socket, callback); m_connectionState = LISTENING; } but when I compile, I get errors that say AcceptHandler type requirements not met
Your version is not the same.
Consider the bind call in the tutorial: it takes a method which accepts
three parameters and binds two of them, producing a functor that accepts
a single error_code argument, which is what is actually passed to
async_accept.
In your case you are trying to pass a function that takes two parameters
to async_accept, which is incompatible. (You're also not actually
providing any value for that first parameter.)
You either need to use bind() as the tutorial does to provide a value
for the function's first parameter, eg:
void ServerSocketASIO::Listen(boost::asio::ip::tcp::acceptor & acceptor,
const std::function
I don't understand.
I want pass around the function object to be called back, because A) I want
the connection class itself to maintain its state B) The connection class
owns the socket and GetSocket() rubs me wrong. C) The server class has
create another connection class and tell it to listen OnAccept.
The problem is, as soon as you introduce std::function to hold it.
Here is a whole listing based purely on the example that works and compiles
fine:
//--------------------------------------
//
// server.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot
com)
//
// Distributed under the Boost Software License, Version 1.0. (See
accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <ctime>
#include <iostream>
#include <string>
#include
If I followed what you wrote in your post correctly, I would end up with:
void start_accept()
{
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.get_io_service());
//auto callback = std::bind(&tcp_server::handle_accept, this,
new_connection, std::placeholders::_1);
const std::function
On 29/03/2017 03:28, Christopher Pisz via Boost-users wrote:
If I followed what you wrote in your post correctly, I would end up with:
void start_accept() { tcp_connection::pointer new_connection = tcp_connection::create(acceptor_.get_io_service());
//auto callback = std::bind(&tcp_server::handle_accept, this, new_connection, std::placeholders::_1); const std::function
callback = std::bind(&tcp_server::handle_accept, this, new_connection, std::placeholders::_1); acceptor_.async_accept(new_connection->socket(), std::bind(callback, this, boost::asio::placeholders::error)); }
Which does not compile. I don't know why I'd bind something that is already bound or what this would mean in the context of the second bind.
All that bind does is to return a functor that has fewer parameters than
another functor, by "binding" some specific values to some parameters
while letting others pass through from the caller. You can bind as many
times as you like (although there's a slight performance hit due to the
indirection).
(Though in this context there's no point in doing two binds -- it's
always possible to write that as a single bind, or as a lambda. You'd
only bind multiple times if it needed to happen in different contexts.)
Now, have a look at the code you wrote:
const std::function
In any case, this is completely different code from what you had in your previous post. I already showed you what to use for your previous code.
What you showed me in the previous code did not work, it did not compile. I am trying to give a thorough complete minimal example, without the complexity of my own classes.
Now, have a look at the code you wrote:
const std::function
callback = std::bind(&tcp_server::handle_accept, this, new_connection, std::placeholders::_1); You are declaring a function that takes a tcp_connection::pointer and a const boost::system::error_code& as parameters -- that's two parameters. But you're only using one placeholder in the bind, which means that the second parameter doesn't go anywhere, which is probably not your intention.
Sigh. I know that code wouldn't work. That is my interpretation of what you
gave me. Now you are talking about two arguments and placeholders, but why
would I give it a place holder, when I am giving it the argument directly?
the tcp_connection::pointer argument is new_connection. The placeholder is
for the error code which I am not supplying directly. Either way, it still
fails to compile if you add a std::placeholders::_2 on the end.
Can we just get a compilable working example of the following method while
maintaining the use of the std::function variable? I don't want to bind
directly, I don't want to use lambda, I want to have an std::function
variable that I can pass to others. It's really a simple 6 line problem....
The following code still fails to compile:
void start_accept()
{
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.get_io_service());
std::function
On 29/03/2017 12:02, Christopher Pisz via Boost-users wrote:
Sigh. I know that code wouldn't work. That is my interpretation of what you gave me. Now you are talking about two arguments and placeholders, but why would I give it a place holder, when I am giving it the argument directly? the tcp_connection::pointer argument is new_connection. The placeholder is for the error code which I am not supplying directly. Either way, it still fails to compile if you add a std::placeholders::_2 on the end.
You need _1 (and only that) in the functor that is passed to async_accept, since that expects a callback that takes exactly one error_code argument. You might need other placeholders if elsewhere you're using functors that take more than one argument, as in one previous instance where you were using multiple binds or getting a callback passed in externally to then rebind locally.
Can we just get a compilable working example of the following method while maintaining the use of the std::function variable? I don't want to bind directly, I don't want to use lambda, I want to have an std::function variable that I can pass to others. It's really a simple 6 line problem....
Just be careful with passing functions outside of the class, as they can have hidden dependencies (eg. the below will UB or crash if something tries to call the callback after tcp_server has been destroyed).
The following code still fails to compile:
void start_accept() { tcp_connection::pointer new_connection = tcp_connection::create(acceptor_.get_io_service());
std::function
callback = std::bind(&tcp_server::handle_accept, this, new_connection, std::placeholders::_1); acceptor_.async_accept(new_connection->socket(), callback); }
I still can't see your monitor from where I'm sitting, so I don't know what errors it produces. If you want anything more helpful than guesswork, then tell people what the errors are; don't just say that it fails. (http://www.catb.org/esr/faqs/smart-questions.html) First off, is that & actually in your source code or is it only being added when you email? You need to fix that if it's actually in your code. Secondly, you shouldn't specify parameter names in the type signature of std::function; just use types. Otherwise, that code looks like it should work, assuming handle_accept has a compatible signature.
Exact source listing in Visual Studio 2015
//
// server.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot
com)
//
// Distributed under the Boost Software License, Version 1.0. (See
accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <ctime>
#include <iostream>
#include <string>
#include
On 29/03/2017 12:02, Christopher Pisz via Boost-users wrote:
Sigh. I know that code wouldn't work. That is my interpretation of what you gave me. Now you are talking about two arguments and placeholders, but why would I give it a place holder, when I am giving it the argument directly? the tcp_connection::pointer argument is new_connection. The placeholder is for the error code which I am not supplying directly. Either way, it still fails to compile if you add a std::placeholders::_2 on the end.
You need _1 (and only that) in the functor that is passed to async_accept, since that expects a callback that takes exactly one error_code argument.
You might need other placeholders if elsewhere you're using functors that take more than one argument, as in one previous instance where you were using multiple binds or getting a callback passed in externally to then rebind locally.
Can we just get a compilable working example of the following method while
maintaining the use of the std::function variable? I don't want to bind directly, I don't want to use lambda, I want to have an std::function variable that I can pass to others. It's really a simple 6 line problem....
Just be careful with passing functions outside of the class, as they can have hidden dependencies (eg. the below will UB or crash if something tries to call the callback after tcp_server has been destroyed).
The following code still fails to compile:
void start_accept() { tcp_connection::pointer new_connection = tcp_connection::create(acceptor_.get_io_service());
std::function
callback = std::bind(&tcp_server::handle_accept, this, new_connection, std::placeholders::_1); acceptor_.async_accept(new_connection->socket(), callback); }
I still can't see your monitor from where I'm sitting, so I don't know what errors it produces. If you want anything more helpful than guesswork, then tell people what the errors are; don't just say that it fails. ( http://www.catb.org/esr/faqs/smart-questions.html)
First off, is that & actually in your source code or is it only being added when you email? You need to fix that if it's actually in your code.
Secondly, you shouldn't specify parameter names in the type signature of std::function; just use types.
Otherwise, that code looks like it should work, assuming handle_accept has a compatible signature.
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
2017-03-29 11:28 GMT+08:00 Christopher Pisz via Boost-users < boost-users@lists.boost.org>:
Exact source listing in Visual Studio 2015
[...]
Exact output spew from compilation: This is against boost 1.55, because that's what I have at home. I use 1.62.0 at work and get the exact same errors.
Change
```
std::function
If I change it to
std::function
2017-03-29 11:28 GMT+08:00 Christopher Pisz via Boost-users < boost-users@lists.boost.org>:
Exact source listing in Visual Studio 2015
[...]
Exact output spew from compilation: This is against boost 1.55, because that's what I have at home. I use 1.62.0 at work and get the exact same errors.
Change ``` std::function
callback = ... ``` To: ``` std::function callback = ... ``` BTW, I'd recommend using lambda exprs instead of bind in most cases.
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
AMDG On 03/29/2017 07:07 AM, Christopher Pisz via Boost-users wrote:
If I change it to std::function
callback = ... then the connection is not passed.
Yes it is. The connection is stored inside the std::function.
If it is not passed, then there is no way to store it, change its state, etc. It is passed in the tutorial code, so why can't I pass it with std::function?
In Christ, Steven Watanabe
So, your whole method looks like:
void start_accept()
{
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.get_io_service());
std::function
AMDG
On 03/29/2017 07:07 AM, Christopher Pisz via Boost-users wrote:
If I change it to std::function
callback = ... then the connection is not passed.
Yes it is. The connection is stored inside the std::function.
If it is not passed, then there is no way to store it, change its state, etc. It is passed in the tutorial code, so why can't I pass it with std::function?
In Christ, Steven Watanabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
AMDG On 03/29/2017 07:41 AM, Christopher Pisz via Boost-users wrote:
So, your whole method looks like:
void start_accept() { tcp_connection::pointer new_connection = tcp_connection::create(acceptor_.get_io_service());
std::function
callback = std::bind(&tcp_server::handle_accept, this, new_connection, std::placeholders::_1); acceptor_.async_accept(new_connection->socket(), callback); }
Seems to compile.
I really don't understand how we are binding arguments that the template parameters did not specify the std::function to take. Can I pass it a cow or a moose too and it won't care? As long as the callback takes a cow and a moose?
Exactly. The error_code is passed as _1. All the other arguments are saved by std::bind and std::function doesn't need to know about them at all.
I thought all arguments had to be specified in the template params.
All the arguments that are passed to the std::function need to be specified. async_accept ends up calling 'callback' with just an error_code. In Christ, Steven Watanabe
Yay. Thanks for the help man. This was driving me batty. -- View this message in context: http://boost.2283326.n4.nabble.com/boost-asio-asyn-accept-handler-tp4693107p... Sent from the Boost - Users mailing list archive at Nabble.com.
participants (4)
-
Christopher Pisz
-
Gavin Lambert
-
Steven Watanabe
-
TONGARI J