Reputation: 30035
I've been writing some javascript and one of the few things I like about the environment is the way it uses promises/futures to make handlers for asynchronous events.
In C++ you have to call .get on a future and it blocks until the result of the future is available but in Javascript you can write .then(fn) and it will call the function when the result is ready. Critically it does this in the same thread as the caller at a later time so there are no thread synchronization issues to worry about, at least not the same ones as in c++.
I'm thinking in c++ something like -
auto fut = asyncImageLoader("cat.jpg");
fut.then([](Image img) { std::cout << "Image is now loaded\n" << image; });
Is there any way to achieve this in c++? Clearly it will need some kind of event queue and event loop to handle dispatching the callbacks. I could probably eventually write the code to do most of this but wanted to see if there was any way to achieve the goal easily using standard facilities.
Upvotes: 22
Views: 12347
Reputation: 11
Use JavaScript-like Promises for C++20. It relies on C++20 coroutines, supports ES6 await/async semantics, and very importantly, it supports 'move' so you can write wrappers for frameworks like asio (e.g. because asio::ip::tcp::socket cannot be copied).
Link: https://github.com/virgil382/JSLikePromise
Upvotes: 1
Reputation: 1439
The question is a bit old, but here is a Javascript-like promise library (consist of a single header that you simply need to include) that aims to do exactly what you ask for, of course together with some sort of async I/O library to implement the actual asyncImageLoader()
.
https://github.com/alxvasilev/cpp-promise
Upvotes: 0
Reputation: 7633
Take a look at https://github.com/Naios/continuable . It supports Javascript style .then()
. It also supports exceptions with .fail()
(instead of .catch()
). There is a great talk about it here https://www.youtube.com/watch?v=l6-spMA_x6g
Upvotes: 1
Reputation: 189
I don't like c++'s future, so i wrote a promise libraries as javascript here https://github.com/xhawk18/promise-cpp
/* Convert callback to a promise (Defer) */
Defer myDelay(boost::asio::io_service &io, uint64_t time_ms) {
return newPromise([&io, time_ms](Defer &d) {
setTimeout(io, [d](bool cancelled) {
if (cancelled)
d.reject();
else
d.resolve();
}, time_ms);
});
}
void testTimer(io_service &io) {
myDelay(io, 3000).then([&] {
printf("timer after 3000 ms!\n");
return myDelay(io, 1000);
}).then([&] {
printf("timer after 1000 ms!\n");
return myDelay(io, 2000);
}).then([] {
printf("timer after 2000 ms!\n");
}).fail([] {
printf("timer cancelled!\n");
});
}
int main() {
io_service io;
testTimer(io);
io.run();
return 0;
}
compare with Javascript promise, just --
You can resolve/reject with any type of paramters, and need not care about the troublesome of <> in c++ template.
Upvotes: 6
Reputation: 275395
While then
is proposed, you can implement your own infix then
via the named operator technique.
Create a struct then_t {};
and a static then_t then;
. Now override operator*
on the left and right so that std::future<bool> *then* lambda
creates a std::async
that waits on the future
, and passes the result to the lambda
, then returns the return value of the lambda.
This requires lots of care and attention, as you have to carefully create copies to avoid dangling references, and mess around with r and l value syntax to make it fully efficient.
The end syntax you get is:
aut fut = asyncLoader("cat.jpg");
fut *then* [&](Image img) { std::cout << "Image loaded: " << img; };
which is pretty close to what you want.
If you are really smart, you could even have it also support:
aut fut = asyncLoader("cat.jpg");
fut *then* [=] { std::cout << "Image loaded: " << fut.get(); };
which gets rid of some of the boilerplate and would be useful sometimes. This requires asyncLoader
to return a std::shared_future
instead of a future
.
Upvotes: 5
Reputation: 54589
A .then
function for std::future
has been proposed for the upcoming C++17 standard.
Boost's implementation of future (which is compliant with the current standard, but provides additional features as extensions) already provides parts of that functionality in newer versions (1.53 or newer).
For a more well-established solution, take a look at the Boost.Asio library, which does allow easy implementation of asynchronous control flows as provided by future.then
. Asio's concept is slightly more complicated, as it requires access to a central io_service
object for dispatching asynchronous callbacks and requires manual management of worker threads. But in principle this is a very good match for what you asked for.
Upvotes: 13
Reputation: 2566
You could pass an object thats for example implementing a Runnable class to the "then" method of the Future class. Once the Future finished its work, call the "run" method of the passed object.
Upvotes: 2