How can I use lambda function within itself? - c++

I have this code and don't know if what I would like to achieve is possible.
_acceptor.async_accept(
_connections.back()->socket(),
[this](const boost::system::error_code& ec)
{
_connections.push_back(std::make_shared<TcpConnection>(_acceptor.get_io_service()));
_acceptor.async_accept(_connections.back()->socket(), this_lambda_function);
}
);
Once a socket is accepted, I would like to reuse the handler (aka the lambda function). Is this possible? Is there a better way to accomplish this?

You have to store a copy of the lambda in itself, using std::function<> (or something similar) as an intermediary:
std::function<void(const boost::system::error_code&)> func;
func = [&func, this](const boost::system::error_code& ec)
{
_connections.push_back(std::make_shared<TcpConnection>(_acceptor.get_io_service()));
_acceptor.async_accept(_connections.back()->socket(), func);
}
_acceptor.async_accept(_connections.back()->socket(), func);
But you can only do it by reference; if you try to capture it by value, it won't work. This means you have to limit the usage of such a lambda to uses were capture-by-reference will make sense. So if you leave this scope before your async function is finished, it'll break.
Your other alternative is to create a proper functor rather than a lambda. Ultimately, lambdas can't do everything.

Related

How to use std::bind for adding member callback to a messenger system

I am currently trying to implement a messenger system for my game engine. It uses function callbacks of the form:
typedef std::function<void(const Message &)> Callback;
I want all objects to be able to subscribe to a message of a specific type (where the type is just a string). Subscribing means adding their "onEvent" function to the dictionary of callbacks.
mutable std::map<std::string, std::vector<Callback>> callbackDictionary;
The update function then calls these functions and passes the according message (from which the "onEvent" functions can get their data)
for each (auto message in messageList)
{
// find the list of respective callbacks
auto it = callbackDictionary.find(message->GetType());
// If there are callbacks registered for this message type
if (it != callbackDictionary.end())
{
// call every registred callback with the appropreate message
for each (auto callback in it->second)
callback(*message);
}
}
Now, my problem is that I am not quite sure how to bind these "onEvent" functions. I have just recently switched to C++11 and the concept of function objects and std::bind is quite new to me. So here is what I have tried:
messageBus.Subscribe("Message/Click",std::bind(&ClickableComponent::OnClick, this));
where the ClickableComponent::OnClick function has the required signature:
void OnClick(const Message &);
and the Subscribe function just adds the passed function to the dictionary
void Messenger::Subscribe(std::string type, Callback callbackFunction) const
{
callbackDictionary[type].push_back(callbackFunction);
}
(The push_back is used because there is a vector of callbacks for each type)
The code seems fine to me but the line:
messageBus.Subscribe("Message/Click", std::bind(&ClickableComponent::OnClick, this));
Gives me the error:
picture of the error discription
I have tried all kinds of stuff like forwarding the Messenger reference and using placeholders, but I have the feeling that I am doing something else wrong. Also, better idea on how to implement this messenger system are appreciated ^^
Thanks for your help!
std::bind is not necessary in your case, lambda function would do just fine:
messageBus.Subscribe("Message/Click", [this](const Message& msg) { OnClick(msg); });
std::bind is more useful in specific cases of metaprogramming.
But if you're curios enough to see how to use std::bind:
messageBus.Subscribe("Message/Click",
std::bind(&ClickableComponent::OnClick, this, std::placeholders::_1));
Here, as you see, you missed std::placeholders::_1. Your functor signature is void(const Message&), but you try to store a member function which signature can be regarded as void(ClickableComponent*, const Message&). To partially apply some arguments (what std::bind does) you need to specify arguments that you'd like to bind and arguments that you leave unbound.
Lambda is preferred because usually it's shorted, more flexible and more readable.

passing boost bind handlers as arguments to asio bind handlers

Are nested boost::bind permissible, and if so what am I doing wrong? I can nest lambda in bind successfully, but not bind in bind.
First example
The simple case
I can manage the standard use boost::bind to pass a complex completion handler invocation where a simple one taking only error code is needed:
socket->receive(buffer, boost::bind(...));
Nested case
but if I want to encapsulate a combination of boost asio operations (e.g. multi-stage async_connect and async_ssl_handshake).
My outer operation will be something like:
connect_and_ssl(socket, boost::bind(...));
and my first stage definition will pass the outer handler on to the second completion in another bind, so that the outer handler can be invoked at the end:
template<typename Socket, typename Handler>
void connect_and_ssl(Socket socket, Handler handler)
{
socket.async_connect(endpoint,
boost::bind(&w::handle_connect, this, socket, handler, boost::asio::placeholders::error));
};
template<typename Socket, typename Handler>
void handle_connect(Socket socket, Handler handler, const boost::system::error_code& ec) {
socket->async_handshake(handler);
}
however handler which is a boost::bind really does not like being part of another boost bind. I get a whole screen full of errors, about not being able to determine the type, and others.
Lambdas work
But I find that I can easily use lambdas instead:
template<typename Socket, typename Handler>
void connect_and_ssl(Socket socket, Handler handler)
{
socket.async_connect(endpoint,
[=](const boost::system::error_code& ec) { handle_connect(socket, handler, ec); } );
};
why? Lambdas are so much easier to write, and understand, but do they make possible something that was impossible with nested binds, or was I just expressing the binds wrongly?
Second example
Simple case
although this will compile:
m_ssl_socket->async_read_some(buffer, m_strand->wrap(handler));
Nested case
when converting to be also invoked from a strand:
m_strand->post(boost::bind(&boost::asio::ssl::stream<boost::asio::ip::tcp::socket&>::async_read_some, m_ssl_socket, buffer, m_strand->wap(handler)));
it will no longer compile - no doubt due to the strand->wrap being inside a boost::bind
Lambda
However the lamda version compiles and runs fine:
m_strand->post([=](){m_ssl_socket->async_read_some(buffer, m_strand->wrap(handler)); } );
I can't work it out, but I'm very glad for lamdas.
Nested bind requires protect.
Boost Bind has it.
In C++11 you have to define one yourself (e.g. using reference_wrapper).

std::function callbacks with asynchronous operations

I want to use std::functions for callback parameters in a wrapper class.
The class wraps a library that allows asynchronous TCP/IP operations (actually boost::asio but neither boost::asio nor TCP/IP should matter here, only that it has asynchronous operations).
The library functions allow me to pass another callback function object that is asynchronously called when the requested operation is finished.
Depending on the result of the asynchronous operation I want to invoke the callback specified by my client or start further operations.
The following code tries to sketch what I intend.
using ConnectHandler = std::function<void(boost::system::error_code ec)>;
class MyConnection
{
public:
void Connect(ConnectHandler handler); // (1)
}
void MyConnection::Connect(ConnectHandler handler)
{
SomeLibrary::async_connect(...,
[handler](boost::system::error_code ec, ...) // (2)
{
//Depending on ec start a nested read/write operation.
//One way or another it finally invokes the callback
handler(ec); // (3)
});
}
The client code would look something like this
MyConnection conn;
conn.Connect([](boost::system::error_code ec)
{
//check ec and start read/write operation
});
My question is:
what is the best way to declare my Connect method in (1), f.e
void Connect(ConnectHandler handler);
void Connect(const ConnectHandler& handler);
void Connect(ConnectHandler&& handler);
and depending on that how do I correctly capture the callback handler in the lambda capture clause in (2) such that I can call it in (3)?
A side note:
the clients instance of MyConnection will never go out of scope until all asynchronous operations have completed!
std::function are cheap to move, so taking it by value is acceptable. Taking by && is mostly pointless, as at best is saves a move. And it forces the caller to move, not copy, and maybe the caller wants to copy?
They are not cheap to copy, so you could consider capturing by move in your callable object.
In C++14, this is as simple as:
[handler=std::move(handler)]
as a capture list (generalized capture expressions).
In C++11 you need to write a custom object to do this.
struct custom_work {
ConnectHandler handler;
void operator()(boost::system::error_code ec, ...) const {
//Depending on ec start a nested read/write operation.
//One way or another it finally invokes the callback
handler(ec); // (3)
}
};
then
SomeLibrary::async_connect(...,
some_work{std::move(handler)}
);
which has the disadvantage of moving the code from inline to out of line.

Why does this ASIO example use members variables to pass state rather than using bind?

In the ASIO HTTP Server 3 example there is code like this:
void server::start_accept()
{
new_connection_.reset(new connection(io_service_, request_handler_));
acceptor_.async_accept(new_connection_->socket(),
boost::bind(&server::handle_accept, this,
boost::asio::placeholders::error));
}
void server::handle_accept(const boost::system::error_code& e)
{
if (!e)
{
new_connection_->start();
}
start_accept();
}
Essentially, new_connection_ is a member of the server class and is used to pass a connection from start_accept to handle_accept. Now, I'm curious as to why new_connection_ is implemented as a member variable.
Wouldn't it also work to pass the connection using bind instead of a member variable? Like this:
void server::start_accept()
{
std::shared_ptr<connection> new_connection(new connection(io_service_, request_handler_));
acceptor_.async_accept(new_connection_->socket(),
boost::bind(&server::handle_accept, this,
boost::asio::placeholders::error),
new_connection);
}
void server::handle_accept(boost::system::error_code const& error, std::shared_ptr<connection> new_connection)
{
if (!error) {
new_connection->start();
}
start_accept();
}
If so, why does the example use member variables? Is it to avoid the copying involved?
(note: I'm not comfortable with ASIO yet and so there may be a fundamental misconception here)
Passing the socket variable inside a function created with std::bind is more or less the same as retaining it as a member variable in the http::server3::server class. Using bind will create temporaries whereas using the member variable will not. I don't think that is a big concern here as the std::shared_ptr is not terribly expensive to copy nor is this code path in the example a performance critical section.
When writing my own applications I find myself using both techniques. If the asynchronous call chain is very long I will typical retain the variables as members to simplify the handler's function signatures and prevent code repetition. For shorter call chains, keeping the state variables in the functor created from bind is a bit easier to understand the code's logic.

Asynchronous write to socket and user values (boost::asio question)

I'm pretty new to boost. I needed a cross platform low level C++ network API, so I chose asio. Now, I've successfully connected and written to a socket, but since I'm using the asynchronous read/write, I need a way to keep track of the requests (to have some kind of IDs, if you will). I've looked at the documentation/reference, and I found no way to pass user data to my handler, the only option I can think of is creating a special class that acts as a callback and keeps track of it's id, then pass it to the socket as a callback. Is there a better way? Or is the best way to do it?
The async_xxx functions are templated on the type of the completion handler. The handler does not have to be a plain "callback", and it can be anything that exposes the right operator() signature.
You should thus be able to do something like this:
// Warning: Not tested
struct MyReadHandler
{
MyReadHandler(Whatever ContextInformation) : m_Context(ContextInformation){}
void
operator()(const boost::system::error_code& error, std::size_t bytes_transferred)
{
// Use m_Context
// ...
}
Whatever m_Context;
};
boost::asio::async_read(socket, buffer, MyReadHander(the_context));
Alternatively, you could also have your handler as a plain function and bind it at the call site, as described in the asio tutorial. The example above would then be:
void
HandleRead(
const boost::system::error_code& error,
std::size_t bytes_transferred
Whatever context
)
{
//...
}
boost::asio::async_read(socket, buffer, boost::bind(&HandleRead,
boost::asio::placeholders::error_code,
boost::asio::placeholders::bytes_transferred,
the_context
));