Quantcast

boost::asio::asyn_accept handler

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

boost::asio::asyn_accept handler

Christopher Pisz
I am looking at the example source at http://www.boost.org/doc/libs/1_62_0/doc/html/boost_asio/tutorial/tutdaytime3/src.html

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/AcceptHandler.html

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?


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: boost::asio::asyn_accept handler

Boost - Users mailing list
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/tutdaytime3/src.html
>
> 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
> &amp;)> 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.


_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: boost::asio::asyn_accept handler

Christopher Pisz
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
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: boost::asio::asyn_accept handler

Christopher Pisz
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.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: boost::asio::asyn_accept handler

Boost - Users mailing list
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 &amp;)> 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.


_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: boost::asio::asyn_accept handler

Christopher Pisz
> 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);
    }







Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: boost::asio::asyn_accept handler

Boost - Users mailing list
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 &amp; 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 &amp; 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
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: boost::asio::asyn_accept handler

Boost - Users mailing list
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 ==========


&amp 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 <[hidden email]> 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 &amp; 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 &amp; 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
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users


_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: boost::asio::asyn_accept handler

Boost - Users mailing list
2017-03-29 11:28 GMT+08:00 Christopher Pisz via Boost-users <[hidden email]>:
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
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: boost::asio::asyn_accept handler

Boost - Users mailing list
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 <[hidden email]> wrote:
2017-03-29 11:28 GMT+08:00 Christopher Pisz via Boost-users <[hidden email]>:
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
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users


_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: boost::asio::asyn_accept handler

Boost - Users mailing list
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
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: boost::asio::asyn_accept handler

Boost - Users mailing list
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 <[hidden email]> 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
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users


_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: boost::asio::asyn_accept handler

Boost - Users mailing list
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

_______________________________________________
Boost-users mailing list
[hidden email]
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: boost::asio::asyn_accept handler

Christopher Pisz
Yay. Thanks for the help man. This was driving me batty.

Loading...