I want to reliaze how to use boost::aio::async_connect with lambda.
Boost version 1.68
It's really strange that I could use std::bind but not lambda.
If I use std::bind, it work.
But when I use lambda, it buillt failed, and said "IteratorConnectHandler type requirements not met.
std::bind version (worked)
void SslClient::connect(boost::asio::ip::tcp::resolver::results_type results) {
auto sp = shared_from_this();
boost::asio::async_connect(ws->next_layer().next_layer(),
results.begin(),
results.end(),
std::bind(
on_connect,
std::placeholders::_1)
);
}
lambda version (not worked)
void SslClient::connect(boost::asio::ip::tcp::resolver::results_type results) {
auto sp = shared_from_this();
boost::asio::async_connect(ws->next_layer().next_layer(),
results.begin(),
results.end(),
[&, sp](boost::system::error_code ec) {
if (ec) {
return;
}
ws->next_layer().async_handshake(boost::asio::ssl::stream_base::client,
[&, sp](boost::system::error_code ec1) {
handShake(ec);
});
}
);
}
So how to use lambda here?
You call async_connect with pair of iterators, so your lambda should meet iterator connect handler requirements. As second parameter you have to pass connected endpoint.
boost::asio::async_connect(ws->next_layer().next_layer(),
results.begin(),
results.end(),
[&, sp]( boost::system::error_code ec,
boost::asio::ip::tcp::resolver::iterator it)
{
if (ec) {
return;
}
//...
To be consistent with reference you should also fix bind version. on_connect should also take iterator as second param.
Your current bind version compiles and works, but when asynchronous operation initiated by async_connect is completed, functor created by bind is called with only error_code, you cannot access endpoint. You can modify bind so that it takes on_connect without any arguments.
void on_connect(){}
boost::asio::async_connect(ws->next_layer().next_layer(),
results.begin(), results.end(), std::bind(on_connect)); // compiles fine
this also compiles, but when handler is called neither error_code nor endpoint can be accessed. (Yes it is a bit strange that you are not getting compiler errors when using bind which inform that requirements of handler are not fulfilled. I don't know where this disagreement between lambda and bind comes from.)
Related
This question involves boost::asio but is a pure C++ 11 question.
I am new to C++ 11 & lambda techniques which I am trying to use with boost::asio::async_connect for network communication.
Following is my function which attempts an asynchronous connect with the host.
bool MyAsyncConnectFunction() {
//some logic here to check validity of host
if (ip_is_not_resolved)
return false;
the_socket.reset(new tcp::socket(the_io_service));
auto my_connection_handler = [this]
(const boost::system::error_code& errc, const tcp::resolver::iterator& itr)
{
if (errc) {
//Set some variables to false as we are not connected
return false;
}
//Do some stuff as we are successfully connected at this point
return true;
};
//How is async_connect taking a lambda which
boost::asio::async_connect(the_socket, IP_destination, tcp::resolver::iterator(), my_connection_handler);
return true;
}
All works fine. There are no functional issues absolutely. However, I am wondering that boost::asio::async_connect takes a ConnectionHandler without a return type in its last parameter but I am passing a lambda i.e. my_connection_handler which returns a value.
How is it possible that I can pass a lambda with a return value whereas boost::asio::async_connect's 4th param takes a callback without a return value ?
boost::asio::async_connect is a function template that takes a callable as its fourth argument. It does not use the return value of said callable, nor does it care about it. Just as you could write :
auto f = []() { return true; };
f(); // Return value is discarded
The example of #m.s. is good too. Since it is a template, the function resolves the argument according to the template argument deduction rules.
Is there any possible way to access the socket handle inside a boost asio async completion handler ? i looked at the boost asio placeholders but there is no variable which stores the socket handle.
You can just arrange for it, anyway you would outside boost or asio.
To bind a function that takes e.g. a socket to expose a void() function you can use bind:
int foo(std::string const& s, int);
std::function<void()> adapted = std::bind(foo, "hello world", 42);
So, usually you'd have code similar to this:
boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
boost::bind(&client::handle_connect, this, boost::asio::placeholders::error));
Note, by using bind and this, we've bound a member function to the completion handler:
struct client
{
// ....
void handle_connect(boost::system::error_code err)
{
// you can just use `this->socket_` here
// ...
}
};
This implies that in handle_connect we can just use the socket_ member variable.
However, if you want to make things complicated you can use free functions as well
boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
boost::bind(&free_handle_connect, boost::ref(socket_), boost::asio::placeholders::error));
Now the implied handler function looks like
static void free_handle_connect(
boost::asio::ip::tcp::socket& socket_,
boost::system::error_code err)
{
// using `socket_` as it was passed in
int fd = _socket.native_handle_type();
}
i am new using c++11 features and also tryng to use SDL_Widget-2 lib for build a simple Gui for my project. But i am getting stuck in the problem :
#include "sdl-widgets.h"
class Builder
{
public:
Builder():top_win(nullptr)
,but(nullptr)
{
top_win=new TopWin("Hello",Rect(100,100,120,100),0,0,false,
[]() {
top_win->clear();
draw_title_ttf->draw_string(top_win->render,"Hello world!",Point(20,40));
}
);
but=new Button(top_win,0,Rect(5,10,60,0),"catch me",
[](Button *b) {
static int dy=60;
b->hide();
b->move(0,dy);
b->hidden=false;
dy= dy==60 ? -60 : 60;
});
}
private:
TopWin * top_win;
Button *but;
};
int main(int,char**) {
Builder aViewBuilder;
get_events();
return 0;
}
with the error in the compilation stage:
In lambda function:
error: 'this' was not captured for this lambda function
error: 'this' was not captured for this lambda function
this error is printed out twice int the console.
I have try :
[this](){}
[=](){}
and
[&](){}
with different compile error but a cannot go more further.
Can any see a fix?
You do need to capture with [this] or [&]. I suspect that the TopWin and Button constructors take raw function pointers, and need to take std::functions instead.
A plain vanilla function pointer is not compatible with capturing lambdas. std::function is able to work like a function pointer that also allows safe storage of captured data. (i.e. the captured objects will need to be properly copied or destroyed when the function object is itself copied or destroyed)
OK, I have a function in C++ that I need to call from JavaScript, and one of the parameters is a JavaScript object. The JavaScript looks like this:
var message = {
fieldA: 42,
fieldB: "moo"
};
myObj.send(message, function (err) { console.log("Result: " + err); });
In the send() routine I need to call a native function in another C library that may block. All functions in this library may block so I've been using uv_queue_work extensively.
This routine is the first time I've hit an issue and it is because of the JavaScript object. The C++ code looks like this:
struct SendMessageRequest
{
Persistent<Object> message;
Persistent<Function> callback;
int result;
};
Handle<Value> MyObj::Send(const Arguments& args)
{
HandleScope scope;
// Parameter checking done but not included here
Local<Object> message = Local<Object>::Cast(args[0]);
Local<Function> callback = Local<Function>::Cast(args[1]);
// Send data to worker thread
SendMessageRequest* request = new SendMessageRequest;
request->message = Persistent<Object>::New(message);
request->callback = Persistent<Function>::New(callback);
uv_work_t* req = new uv_work_t();
req->data = request;
uv_queue_work(uv_default_loop(), req, SendMessageWorker, SendMessageWorkerComplete);
return scope.Close(Undefined());
}
This is all fine, the problem comes when I try to access request->message in the SendMessageWorker function.
void SendMessageWorker(uv_work_t* req)
{
SendMessageRequest* request = (SendMessageRequest*)req->data;
Local<Array> names = request->message->GetPropertyNames();
// CRASH
It seems that calling methods off of request->message causes an Access Violation on a really small address (probably a NULL pointer reference somewhere in V8/node). So using request->message directly must be wrong. I know to access the callback function I need to do this:
request->callback->Call(Context::GetCurrent()->Global(), 1, argv);
Do I need to use Context::GetCurrent()->Global() in order to access methods off of the Object class that is wrapped by the Persistent template? If so how do I do that?
The code in SendMessageWorker is not executed on the JavaScript - what uv_queue_work does is execute your SendMessageWorker in a separate thread, so it can let the node.js code run as well, and when it's ready, SendMessageWorkerComplete is executed back on the JavaScript thread.
So you can't use JavaScript variables in SendMessageWorker - if you really need to, you'd have to convert them to e.g. C++ string before calling uv_queue_work.
I am trying to write a function which, given a number of seconds and a callback, runs the callback after the given number of seconds. The callback does not have to be on the same thread. The target language is C++/CX.
I tried using Windows::System::Threading::ThreadPoolTimer, but the result is a memory access exception. The issue appears to be that the callback implementation (in native C++) can't be accessed from the managed thread that the timer is running its callback on.
ref class TimerDoneCallback {
private:
function<void(void)> m_callback;
public:
void EventCallback(ThreadPoolTimer^ timer) {
m_callback(); // <-- memory exception here
}
TimerDoneCallback(function<void(void)> callback) : m_callback(callback) {}
};
void RealTimeDelayCall(const TimeSpan& duration, function<void(void)> callback) {
auto t = ref new TimerDoneCallback(callback);
auto e = ref new TimerElapsedHandler(t, &TimerDoneCallback::EventCallback);
ThreadPoolTimer::CreateTimer(e, duration);
}
void Test() {
RealTimeDelayCall(duration, [](){}); //after a delay, run 'do nothing'
}
I don't want to create a thread and sleep on it, because there may be many concurrent delays.
The TimerDoneCallback instance is not kept alive - delegates in C++/CX take weak references to the target object (to avoid circular references). You can override this behavior by using the extended overload of the delegate constructor:
auto e = ref new TimerElapsedHandler(t, &TimerDoneCallback::EventCallback, CallbackContext::Any, true);
The final bool parameter should be true for strong references, and false for weak references. (False is the default.)
You could also consider using the timer class in PPL agents to make a delayed callback: http://msdn.microsoft.com/en-us/library/hh873170(v=vs.110).aspx to avoid needing to use ThreadPoolTimer.