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<void(ServerSocketASIO *, const boost::system::error_code &)> callback) { acceptor.async_accept(m_socket, callback); m_connectionState = LISTENING; } but when I compile, I get errors that say AcceptHandler type requirements not met If I implement it this way: void ServerSocketASIO::Listen(boost::asio::ip::tcp::acceptor & acceptor, std::function<void(const boost::system::error_code &)> callback) { acceptor.async_accept(m_socket, callback); m_connectionState = LISTENING; } It compiles, but I would need the actual connection to put into a collection of some kind, in order to keep track of connected clients. The documentation I found at http://www.boost.org/doc/libs/1_62_0/doc/html/boost_asio/reference/AcceptHan... Only shows the accept callback with a boost::system::error_code argument. So, my question is, is the example source wrong? and How do I pass my own connection class to the callback? -- View this message in context: http://boost.2283326.n4.nabble.com/boost-asio-asyn-accept-handler-tp4693107.... Sent from the Boost - Users mailing list archive at Nabble.com.

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<void(ServerSocketASIO *, const boost::system::error_code &)> 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<void(ServerSocketASIO *, const boost::system::error_code&)>& callback) { acceptor.async_accept(m_socket, boost::bind(callback, this, boost::asio::placeholders::error)); m_connectionState = LISTENING; } Or you need to use a lambda that does the equivalent: void ServerSocketASIO::Listen(boost::asio::ip::tcp::acceptor & acceptor, const std::function<void(ServerSocketASIO *, const boost::system::error_code&)>& callback) { acceptor.async_accept(m_socket, [=](const boost::system::error_code& ec) { callback(this, ec); }); m_connectionState = LISTENING; } Alternatively you might want to consider having the callback be a member method as shown in the tutorial as this usually provides better encapsulation. (You'll still need to bind it though.) Another thing to possibly be careful of is the order of statements inside Listen -- depending on several factors, it's possible for the callback to be called before m_connectionState is assigned, which might surprise other logic in your class. Consider assigning it before the call to async_accept.

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 <boost/bind.hpp> #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/asio.hpp> using boost::asio::ip::tcp; std::string make_daytime_string() { using namespace std; // For time_t, time and ctime; time_t now = time(0); return ctime(&now); } class tcp_connection : public boost::enable_shared_from_this<tcp_connection> { public: typedef boost::shared_ptr<tcp_connection> pointer; static pointer create(boost::asio::io_service& io_service) { return pointer(new tcp_connection(io_service)); } tcp::socket& socket() { return socket_; } void start() { message_ = make_daytime_string(); boost::asio::async_write(socket_, boost::asio::buffer(message_), boost::bind(&tcp_connection::handle_write, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } private: tcp_connection(boost::asio::io_service& io_service) : socket_(io_service) { } void handle_write(const boost::system::error_code& /*error*/, size_t /*bytes_transferred*/) { } tcp::socket socket_; std::string message_; }; class tcp_server { public: tcp_server(boost::asio::io_service& io_service) : acceptor_(io_service, tcp::endpoint(tcp::v4(), 13)) { start_accept(); } private: 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); acceptor_.async_accept(new_connection->socket(), callback); } void handle_accept(tcp_connection::pointer new_connection, const boost::system::error_code& error) { if (!error) { new_connection->start(); } start_accept(); } tcp::acceptor acceptor_; }; int main() { try { boost::asio::io_service io_service; tcp_server server(io_service); io_service.run(); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } return 0; } //-------------------------------------- Now change auto to std::function and it no longer compiles: void start_accept() { tcp_connection::pointer new_connection = tcp_connection::create(acceptor_.get_io_service()); std::function<void (tcp_connection::pointer new_connection, const boost::system::error_code & error)> callback = std::bind(&tcp_server::handle_accept, this, new_connection, std::placeholders::_1); acceptor_.async_accept(new_connection->socket(), callback); } //------------------------------------ So, how do I store the callback, such that I can pass it around? Because, my goal is to move this the code in "tcp_server::start_accept" to "tcp_connection::Listen" and just have tcp_server::start that calls tcp_connection::Listen -- 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.

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<void(tcp_connection::pointer, const boost::system::error_code &)> 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. -- 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.

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<void(tcp_connection::pointer, const boost::system::error_code &)> 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<void(tcp_connection::pointer, const boost::system::error_code&)> 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. Meanwhile in the second bind you're trying to mix boost binding with std binding. Either use boost::bind for the async_accept call or use std::placeholders::_1 instead of the boost::asio::placeholders::error. Also, "this" is probably not a tcp_connection::pointer, so it's not valid to try to bind that to the first parameter of callback. (You can mix binds to a certain extent -- a boost bind can be stored in a std::function and vice versa, and you can boost bind a std::function and vice versa, but you can't use std:: placeholders in a boost:: bind and vice versa.) 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.

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<void(tcp_connection::pointer, const boost::system::error_code&)> 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<void(tcp_connection::pointer new_connection, const boost::system::error_code & error)> callback = std::bind(&tcp_server::handle_accept, this, new_connection, std::placeholders::_1); acceptor_.async_accept(new_connection->socket(), callback); } -- 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.

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<void(tcp_connection::pointer new_connection, const boost::system::error_code & error)> 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 <boost/bind.hpp> #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/asio.hpp> #include <functional> using boost::asio::ip::tcp; std::string make_daytime_string() { using namespace std; // For time_t, time and ctime; time_t now = time(0); return ctime(&now); } class tcp_connection : public boost::enable_shared_from_this<tcp_connection> { public: typedef boost::shared_ptr<tcp_connection> pointer; static pointer create(boost::asio::io_service& io_service) { return pointer(new tcp_connection(io_service)); } tcp::socket& socket() { return socket_; } void start() { message_ = make_daytime_string(); boost::asio::async_write(socket_, boost::asio::buffer(message_), boost::bind(&tcp_connection::handle_write, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } private: tcp_connection(boost::asio::io_service& io_service) : socket_(io_service) { } void handle_write(const boost::system::error_code& /*error*/, size_t /*bytes_transferred*/) { } tcp::socket socket_; std::string message_; }; class tcp_server { public: tcp_server(boost::asio::io_service& io_service) : acceptor_(io_service, tcp::endpoint(tcp::v4(), 13)) { start_accept(); } private: void start_accept() { tcp_connection::pointer new_connection = tcp_connection::create(acceptor_.get_io_service()); std::function<void(tcp_connection::pointer new_connection, const boost::system::error_code &error)> callback = std::bind(&tcp_server::handle_accept, this, new_connection, std::placeholders::_1); acceptor_.async_accept(new_connection->socket(), callback); } void handle_accept(tcp_connection::pointer new_connection, const boost::system::error_code& error) { if( !error ) { new_connection->start(); } start_accept(); } tcp::acceptor acceptor_; }; int main() { try { boost::asio::io_service io_service; tcp_server server(io_service); io_service.run(); } catch( std::exception& e ) { std::cerr << e.what() << std::endl; } return 0; } 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. 1> Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example: 1> - add -D_WIN32_WINNT=0x0501 to the compiler command line; or 1> - add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions. 1> Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). 1>d:\programing projects\cplusplus\boost_1_55_0\boost\asio\detail\impl\socket_ops.ipp(1953): warning C4996: 'WSAAddressToStringA': Use WSAAddressToStringW() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings 1> c:\program files (x86)\windows kits\8.1\include\um\winsock2.h(3556): note: see declaration of 'WSAAddressToStringA' 1>d:\programing projects\cplusplus\boost_1_55_0\boost\asio\detail\impl\socket_ops.ipp(2159): warning C4996: 'WSAStringToAddressA': Use WSAStringToAddressW() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings 1> c:\program files (x86)\windows kits\8.1\include\um\winsock2.h(3623): note: see declaration of 'WSAStringToAddressA' 1>d:\programing projects\cplusplus\boost_1_55_0\boost\asio\detail\impl\socket_ops.ipp(2295): warning C4996: 'gethostbyaddr': Use getnameinfo() or GetNameInfoW() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings 1> c:\program files (x86)\windows kits\8.1\include\um\winsock2.h(2216): note: see declaration of 'gethostbyaddr' 1>d:\programing projects\cplusplus\boost_1_55_0\boost\asio\detail\impl\socket_ops.ipp(2344): warning C4996: 'gethostbyname': Use getaddrinfo() or GetAddrInfoW() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings 1> c:\program files (x86)\windows kits\8.1\include\um\winsock2.h(2238): note: see declaration of 'gethostbyname' 1>d:\programing projects\cplusplus\boost_1_55_0\boost\asio\detail\impl\socket_select_interrupter.ipp(62): warning C4996: 'inet_addr': Use inet_pton() or InetPton() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings 1> c:\program files (x86)\windows kits\8.1\include\um\winsock2.h(1850): note: see declaration of 'inet_addr' 1>d:\programing projects\cplusplus\boost_1_55_0\boost\asio\detail\impl\socket_select_interrupter.ipp(75): warning C4996: 'inet_addr': Use inet_pton() or InetPton() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings 1> c:\program files (x86)\windows kits\8.1\include\um\winsock2.h(1850): note: see declaration of 'inet_addr' 1>d:\users\cpisz.christopherpisz\documents\visual studio 2015\projects\consoleapplication1\consoleapplication1\source2.cpp(27): warning C4996: 'ctime': This function or variable may be unsafe. Consider using ctime_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. 1> c:\program files (x86)\windows kits\10\include\10.0.10240.0\ucrt\time.h(475): note: see declaration of 'ctime' 1>d:\programing projects\cplusplus\boost_1_55_0\boost\asio\basic_socket_acceptor.hpp(1015): error C2338: AcceptHandler type requirements not met 1> d:\users\cpisz.christopherpisz\documents\visual studio 2015\projects\consoleapplication1\consoleapplication1\source2.cpp(91): note: see reference to function template instantiation 'boost::asio::async_result<Handler>::type boost::asio::basic_socket_acceptor<boost::asio::ip::tcp,boost::asio::socket_acceptor_service<Protocol>>::async_accept<Protocol,StreamSocketService,std::function<void (tcp_connection::pointer,const boost::system::error_code &)>&>(boost::asio::basic_socket<Protocol,StreamSocketService> &,AcceptHandler,void *)' being compiled 1> with 1> [ 1> Handler=std::function<void (tcp_connection::pointer,const boost::system::error_code &)>, 1> Protocol=boost::asio::ip::tcp, 1> StreamSocketService=boost::asio::stream_socket_service<boost::asio::ip::tcp>, 1> AcceptHandler=std::function<void (tcp_connection::pointer,const boost::system::error_code &)> & 1> ] 1> d:\users\cpisz.christopherpisz\documents\visual studio 2015\projects\consoleapplication1\consoleapplication1\source2.cpp(91): note: see reference to function template instantiation 'boost::asio::async_result<Handler>::type boost::asio::basic_socket_acceptor<boost::asio::ip::tcp,boost::asio::socket_acceptor_service<Protocol>>::async_accept<Protocol,StreamSocketService,std::function<void (tcp_connection::pointer,const boost::system::error_code &)>&>(boost::asio::basic_socket<Protocol,StreamSocketService> &,AcceptHandler,void *)' being compiled 1> with 1> [ 1> Handler=std::function<void (tcp_connection::pointer,const boost::system::error_code &)>, 1> Protocol=boost::asio::ip::tcp, 1> StreamSocketService=boost::asio::stream_socket_service<boost::asio::ip::tcp>, 1> AcceptHandler=std::function<void (tcp_connection::pointer,const boost::system::error_code &)> & 1> ] 1>d:\programing projects\cplusplus\boost_1_55_0\boost\asio\basic_socket_acceptor.hpp(1015): error C2064: term does not evaluate to a function taking 1 arguments 1> d:\programing projects\cplusplus\boost_1_55_0\boost\asio\basic_socket_acceptor.hpp(1015): note: class does not define an 'operator()' or a user defined conversion operator to a pointer-to-function or reference-to-function that takes appropriate number of arguments ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== & somehow got put there from copy pasting? It is an actual amperstand in code. I am posting via Gmail now. I am not sure if they did it. At work I have to post through nabble, because they have just about everything blocked. On Tue, Mar 28, 2017 at 9:23 PM, Gavin Lambert via Boost-users < boost-users@lists.boost.org> wrote:
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<void(tcp_connection::pointer new_connection, const boost::system::error_code & error)> 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<void(tcp_connection::pointer new_connection, const boost::system::error_code &error)> callback = ... ``` To: ``` std::function<void(const boost::system::error_code &error)> callback = ... ``` BTW, I'd recommend using lambda exprs instead of bind in most cases.

If I change it to std::function<void(const boost::system::error_code &error)> callback = ... then the connection is not passed. 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? On Wed, Mar 29, 2017 at 12:56 AM, TONGARI J via Boost-users < boost-users@lists.boost.org> wrote:
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<void(tcp_connection::pointer new_connection, const boost::system::error_code &error)> callback = ... ``` To: ``` std::function<void(const boost::system::error_code &error)> 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<void(const boost::system::error_code &error)> 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<void(const boost::system::error_code &error)> 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? I thought all arguments had to be specified in the template params. On Wed, Mar 29, 2017 at 8:28 AM, Steven Watanabe via Boost-users < boost-users@lists.boost.org> wrote:
AMDG
On 03/29/2017 07:07 AM, Christopher Pisz via Boost-users wrote:
If I change it to std::function<void(const boost::system::error_code &error)> 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<void(const boost::system::error_code &error)> 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