C++14 asynchronous allocation aware futures (supporting then, exception handling, coroutines and connections)

Continuable

Current version Travic-CI build status AppVeyor CI status MIT Licensed Documentation Try continuable online Compiler explorer


Continuable is a C++14 library that provides full support for:

  • lazy async continuation chaining based on callbacks (then) and expression templates, callbacks are wrapped nicely as promises.
  • no enforced type-erasure which means we need less heap allocations than comparable libraries, strictly following the "don't pay for what you don't use" principle.
  • support for all, any and sequential connections between continuables through expressive operator overloads &&, || and >> as well as free functions when_all, when_any and when_seq.
  • asynchronous error handling through exceptions, error codes and user defined types.
  • syntactic sugar for instance: partial invocation, tuple unpacking, co_await support and executors.
  • encapsuled from any runtime, larger framework or executors makes it possible to use continuable even in smaller or esoteric usage scenarios.

Getting started:

The documentation offers everything you need:

Issues and contributions

Issue reports and questions are accepted through the Github issue tracker as well as pull requests. Every contribution is welcome! Don't hesitate to ask for help if you need any support in improving the implementation or if you have any troubles in using the library

Quick Tour

  • Create a continuable through make_continuable which returns a promise on invocation:

    auto http_request(std::string url) {
      return cti::make_continuable<std::string>([url = std::move(url)](auto&& promise) {
        // Perform the actual request through a different library,
        // resolve the promise upon completion of the task.
        promise.set_value("<html> ... </html>");
        // or: promise.set_exception(std::make_exception_ptr(std::exception("Some error")));
        // or: promise.set_canceled();
      });
    }
    
    auto mysql_query(std::string query) {
      return cti::make_continuable<result_set, bool>([url = std::move(url)](auto&& promise) {
        //                         ^^^^^^^^^^^^^^ multiple result types
      });
    }
    
    auto do_sth() {
      return cti::make_continuable<void>([](auto&& promise) {
        //                         ^^^^ no result at all
      });
    }
    
    auto run_it() {
      return async([] {
        // Directly start with a handler
      });
    }
    
    continuable<> run_it() { // With type erasure
      return async([] {
    
      });
    }
  • Attach your continuations through then, supports multiple results and partial handlers:

    mysql_query("SELECT `id`, `name` FROM `users`")
      .then([](result_set users) {
        // Return the next continuable to process ...
        return mysql_query("SELECT `id` name FROM `sessions`");
      })
      .then([](result_set sessions) {
        // ... or pass multiple values to the next callback using tuples or pairs ...
        return std::make_tuple(std::move(sessions), true);
      })
      .then([](result_set sessions, bool is_ok) {
        // ... or pass a single value to the next callback ...
        return 10;
      })
      .then([](auto value) {
        //     ^^^^ Templated callbacks are possible too
      })
      // ... you may even pass continuables to the `then` method directly:
      .then(mysql_query("SELECT * `statistics`"))
      .then([](result_set result) {
        // ...
          return "Hi";
      })
      .then([] /*(std::string result) */ { // Handlers can accept a partial set of arguments{
        // ...
      });
  • Handle failures through fail or next:

    http_request("example.com")
      .then([] {
        throw std::exception("Some error");
      })
      .fail([] (std::exception_ptr ptr) {
        if (ptr) {
          try {
            std::rethrow_exception(ptr);
          } catch(std::exception const& e) {
            // Handle the exception or error code here
          }
        }
      });
  • Dispatch continuations through a specific executor (possibly on a different thread or later)

    auto executor = [](auto&& work) {
      // Dispatch the work here, store it for later invocation or move it to another thread.
      std::forward<decltype(work)>(work)();
    };
    
    read_file("entries.csv")
      .then([](Buffer buffer) {
        // ...
      }, executor);
    //   ^^^^^^^^
  • Connect continuables through when_all, when_any or when_seq:

    // `all` of connections:
    (http_request("github.com") && http_request("example.com") && http_request("wikipedia.org"))
      .then([](std::string github, std::string example, std::string wikipedia) {
        // The callback is called with the response of github,
        // example and wikipedia.
      });
    
    // `any` of connections:
    (http_request("github.com") || http_request("example.com") || http_request("wikipedia.org"))
      .then([](std::string github_or_example_or_wikipedia) {
        // The callback is called with the first response of either github,
        // example or wikipedia.
      });
    
    // `sequence` of connections:
    (http_request("github.com") >> http_request("example.com") >> http_request("wikipedia.org"))
      .then([](std::string github, std::string example, std::string wikipedia) {
        // The requests are invoked sequentially
      });
    
    // Mixed logical connections:
    (http_request("github.com") && (http_request("example.com") || http_request("wikipedia.org")))
      .then([](std::string github, std::string example_or_wikipedia) {
        // The callback is called with the response of github for sure
        // and the second parameter represents the response of example or wikipedia.
      });
    
    // There are helper functions for connecting continuables:
    auto all = cti::when_all(http_request("github.com"), http_request("example.com"));
    auto any = cti::when_any(http_request("github.com"), http_request("example.com"));
    auto seq = cti::when_seq(http_request("github.com"), http_request("example.com"));
  • Deal with multiple result variables through result and recover from failures:

    make_exceptional_continuable<void>(std::make_exception_ptr(std::exception("Some error"))
      .fail([] (std::exception_ptr ptr) {
        return recover();
      })
      .then([] () -> result<> {
        // We recovered from the failure and proceeding normally
    
        // Will yield a default constructed exception type to signal cancellation
        return cancel();
      });
  • promisify your existing code or use the (asio) completion token integration:

    // Promisification of your existing code that accepts callbacks
    auto async_resolve(std::string host, std::string service) {
      return cti::promisify<asio::ip::udp::resolver::iterator>::from(
          [&](auto&&... args) {
            resolver_.async_resolve(std::forward<decltype(args)>(args)...);
          },
          std::move(host), std::move(service));
    }
    
    // (boost) asio completion token integration
    asio::io_context io_context;
    asio::steady_timer steady_timer(io_context);
    
    steady_timer.expires_after(std::chrono::seconds(5));
    steady_timer.async_wait(cti::use_continuable)
      .then([] {
        // Is called after 5s
      });
  • C++20 Coroutine support:

    (co_await and co_return) are supported by continuable when the underlying toolchain supports the TS. Currently this works in MSVC 2017 and Clang 5.0. You have to enable this capability through the CTI_CONTINUABLE_WITH_AWAIT define in CMake:

    int i = co_await cti::make_continuable<int>([](auto&& promise) {
      promise.set_value(0);
    });

Appearances:

MeetingC++ 2018 Talk
Continuable MeetingC++]

.

Owner
Denis Blank
⭐️ Compiler and C++ metaprogramming enthusiast
Denis Blank
Comments
  • First class, zero-overhead ASIO integration

    First class, zero-overhead ASIO integration

    @Naios

    You may remember a long while back you and I e-mailed about the possibility of a first-class ASIO integration for continuable. This was not possible at the time due to

    1. eager initiation of the async op
    2. need to specify explicitly the return_type of a continuation chain, therefore requiring type erasure.

    In boost 1.70 requirement 1. was lifted, see the 2nd bullet on the 1.70 release: https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio/history.html

    And now the pending changes in Boost 1.72 remove restriction 2, you can peruse, e.g., https://github.com/boostorg/asio/commit/3f680fe1f732cec6493672425d0de9fac0a11618 https://github.com/boostorg/asio/commit/77b14fff7f63ca69fbb80e6a9fe97ff56f661a43

    I have implemented an integration on a fork here: https://github.com/Naios/continuable/compare/master...cstratopoulos:feature/asio-async-result

    I wanted to open a corresponding PR, but thought it best to run it by you beforehand as there are some design/integration points I wanted to run by you

    I initially tried to do this using cti::promisify, but I think this is not possible. The async_result::initiate behaves like, quoting the docs,

    std::forward<Initiation>(initiation)(std::move(handler), std::forward<Args>(args)...)
    

    in our case handler is synthesized by binding a promise to a continuable Resolver type, so we need access to the promise&& parameter of the continuation, which is not present when using promisify. You will see, however, that my implementation duplicates the implementation of promisify to a considerable extent.

    Second, I was wondering if you would like this to remain as an example or if you would consider promoting it to the main library, with a suitable macro/config guard. My reasoning is that specializing async_result lies some levels of detail below what a typical user would want to delive into in their hopes of using asio/continuable to be able to write, e.g,, http_request("github.com").then(/* ... */);. This is a composable, pluggable utility rather than the sort of one-off adapters generated by cti::promisify as illustrated in the existing ASIO example.

    Naturally, I imagine you do not want to bind an ASIO dependency into the main library. I think this could be reasonable as an opt-in mechanism which guards the entire header with macros, similar, e.g., to coroutine support detection.

    If you are open to that, I wanted furthermore to float the possibility that, with some (relatively minor) macro shenanigans around namespaces and include paths, it should be possible to have one header file which provides support for both standalone asio and boost asio.

    To sketch an implementation, one might define, e.g., CTI_WITH_STANDALONE_ASIO or CTI_WITH_BOOST_ASIO, which could in turn make CTI_ASIO_NAMESPACE BEGIN resolve to either namespace asio { or namespace boost { namespace asio{. A similar approach should take care of the include paths for async_result and error_code, and I think the remaining code would be largely unchanged.

  • ASIO integration

    ASIO integration

    @Naios

    Here is the preliminary PR for #27 . Opening it now so we can discuss/improve with code review features, but it is not ready to merge. The main blockers are

    • the release of Boost 1.72
    • the release of standalone ASIO 1.15 (I believe)

    This is required of course for the new form of async_result, but also to get rid of a bug workaround for MSVC detection of auto return type support (workaround here, bug report here)

    However there are other things I wanted to flag for your approval or discussion, mostly related to error handling.

    1. Note the current example calls std::make_exception_ptr(asio::error_code). From the std::make_exception_ptr documentation, this suggests that such errors will only be caught in a .fail handler if the user does catch(asio::error_code const&). However I think this is not standard, as the usual approach for moving from error codes to exceptions would be to throw/catch an asio::system_error constructed from an asio::error_code. If my assessment is correct I can amend the line linked above to do make_exception_ptr(system_error(e)). This is also why I added the cancelled_async_wait example, to be sure exceptions can be caught as expected.

    2. Consequently from 1., the distribution-specific detail code has some logic to establish the pair exception_t and error_code_t such that the former is constructible from the latter. This is a divergence from our discussion in #27 where we thought all mention of the error_code type could be elided by having a lambda handler with an auto ec parameter. Since we're already doing this, I used the error_code_t in the continuable_result<Signature> specializations. I think this could be done with specializations for template<typename Error, typename T>, but this is a bit cleaner and clearer in my opinion. a) This is also why I put use_cti_t back in the ASIO namespace, since it fits the convention of other ASIO helper tokens (e.g., use_future_t), and we have to muck around in the ASIO namespace anyway. But if you like I can just make it cti::asio_token_t or similar!

    3. Currently the code only works with exception handling enabled. The standard default for no exceptions is an std::error_condition, which will work in the standalone ASIO case (where the error types alias the corresponding std types), but not with Boost, which uses Boost.System. I think we can accommodate a couple options. If exceptions are enabled, this fits with the ASIO use_future_t error handling mechanism for std::future which stores exceptions with std::promise::set_exception(std::exception_ptr). Also, users may want to set CONTINUABLE_WITH_CUSTOM_ERROR_TYPE to asio::error_code or boost::system::error_code, which would also be in line with idiomatic ASIO error handling. Finally, users may have the error type set to std::error_condition either by disabling continuable's exceptions, with a custom error type, or they may set it to boost::system::error_condition. That one feels maybe less likely/more awkward to me, but it's possible. Anyway to sketch a solution,

    // distribution-specific aliases
    using error_code_t = ...
    using error_cond_t = ...
    using exception_t = ...
    
    template<typename Promise>
    auto promise_fail_helper(Promise& p, error_code_t ec) 
        -> decltype(p.set_exception(ec)) { p.set_exception(ec); }
    
    template<typename Promise>
    auto promise_fail_helper(Promise& p, error_code_t ec)
     -> decltype(p.set_exception(error_cond_t(ec.value(), ec.category()))
    { p.set_exception(error_cond_t(ec.value(), ec.category())) }
    
    template<typename Promise>
    auto promise_fail_helper(Promise& p, error_code_t ec) 
        -> decltype(p.set_exception(std::make_exception_ptr(exception_t(ec)))) 
    { p.set_exception(std::make_exception_ptr(exception_t(ec))); }
    

    to respect the setting of CONTINUABLE_WITH_NO_EXCEPTIONS, the exception_t alias and overloads may be guarded with an #ifdef. And since promise_base::set_exception only accepts cti::exception_t, I think there is no overload ambiguity. Anyway let me know your thoughts and I can pursue the sketch solution above if it sounds reasonable to you.

    Check lists (check x in [ ] of list items)

    • [ ] Additional Unit Tests were added that test the feature or regression
    • [X] Coding style (Clang format was applied)

    I applied clang-format while editing the code. As for unit tests, the added example tries to test the robustness of completion handler signatures ( void(error_code), void(error_code, T)) and correctness of error handling. This could be added to a unit test with asserts, but I am not sure if this is an approach you want to take.

  • Infinite recursion during compilation

    Infinite recursion during compilation

    Hi @Naios

    Our team develops https://github.com/soramitsu/kagome/ in C++17. We decided to use continuable instead of callbacks to simplify our code.

    We integrated latest master (42af23f) and started to refactor interfaces.

    Me and my team mate (separately) run into the same problem of infinite recursion during compilation. We both use latest Mac OS, latest CLion for development, same compiler (Apple LLVM version 10.0.1 (clang-1001.0.46.4)).

    In my case, it occurred after I added this chain (branch feature/ref-transport-continuable): https://github.com/soramitsu/kagome/blob/feature/ref-transport-continuable/core/libp2p/transport/tcp/tcp_transport.cpp#L29

    It looks legit, and I don't see any bugs there, but when you build tcp_transport target, it just never finishes (recurses infinitely). At some point I run out of disk space (clangd consumed more than 70GB) and compilation died.

    Steps to reproduce: I don't have time to create small self-container repo with repro code, but instead I will just share our project.

    1. git clone --recursive https://github.com/soramitsu/kagome/
    2. cd kagome
    3. mkdir build
    4. cd build
    # this step may take a while, since hunter builds all our dependencies during cmake time
    # after it completes, you can remove ~/.hunter
    5. cmake .. 
    6. make tcp_transport
    
  • Need help - continuation keeps blocking

    Need help - continuation keeps blocking

    Hello, I am running event loop in 2 threads to process incoming request. I have tried to use your library to avoid blocking the socket while getting data from database. However even with the continuation, the thread is blocked during the full execution.

    auto handle_report(string &report_name, string &destination_directory, vector<json> &data)
    {
    	return cti::make_continuable<vector<vector<string>>, ExcelSchema>(
    		[&report_name,
    		 &destination_directory,
    		 &data](auto &&promise) {
      vector<vector<string>> results;
    ExcelSchema schema;
    //I connect to Oracle and get data and also populate schema object
    try{
    promise.set_value(move(results), move(schema));
    }
    catch (exception &e)
    			{
    				promise.set_exception(std::current_exception());
    			}
    

    And then on my socket callback I write to a file and in last continuation once it is done I send reply back.

    handle_report(report_name, destination_directory, data).then([&download_folder, &dateformat](vector<vector<string>> results, ExcelSchema schema) {
    
    			//write results to temporary xlsx file
    			boost::filesystem::path file_name("/temp.xlsx");
    			boost::filesystem::path report_file = download_folder / file_name;
    			string dest_filename = report_file.string();
    
    			lxw_workbook_options options = {.constant_memory = LXW_TRUE, .tmpdir = NULL};
    			lxw_workbook *workbook = workbook_new_opt(dest_filename.c_str(), &options);
    			lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
    
    			lxw_format *legend_format = workbook_add_format(workbook);
    			format_set_bold(legend_format);
    			format_set_align(legend_format, LXW_ALIGN_CENTER);
    			lxw_format *date_format = workbook_add_format(workbook);
    			format_set_num_format(date_format, "dd-mmm-yy");
    			lxw_format *number_format = workbook_add_format(workbook);
    			format_set_num_format(number_format, "0.00");
    			schema.createLegend(results[0]);
    			vector<string> read_types = schema.getReadTypes();
    			for (uint32_t row = 0; row < results.size(); ++row)
    			{
    				for (uint32_t col = 0; col < results[row].size(); ++col)
    				{
    					string value = results[row][col];
    					if (value != "NULL")
    					{
    						if (row == 0)
    						{
    							worksheet_write_string(worksheet, row, col, value.c_str(), legend_format);
    						}
    						else if (read_types[col] == "string")
    						{
    							worksheet_write_string(worksheet, row, col, value.c_str(), nullptr);
    						}
    						else if (read_types[col] == "number")
    						{
    							double value_num;
    							istringstream ss(value);
    							ss >> value_num;
    							worksheet_write_number(worksheet, row, col, value_num, number_format);
    						}
    						else if (read_types[col] == "date")
    						{
    							Date date(value, dateformat);
    							lxw_datetime datetime = {date.GetYear(), date.GetMonth(), date.GetDay(), 0, 0, 0.0};
    							worksheet_write_datetime(worksheet, row, col, &datetime, date_format);
    						}
    						else
    						{
    							throw invalid_argument("Unexpected column type: " + read_types[col]);
    						}
    					}
    				}
    			}
    			workbook_close(workbook);
    
    			//load file into memory and delete temp file
    			std::ifstream t(dest_filename.c_str());
    			std::string temp_data((std::istreambuf_iterator<char>(t)),
    								  std::istreambuf_iterator<char>());
    			t.close();
    			boost::filesystem::remove(dest_filename);
    
    			return temp_data;
    		})
    		.then([&req](string data) {
    			//send response
    			static h2o_generator_t generator = {NULL, NULL};
    			h2o_iovec_t body = h2o_strdup(&req->pool, data.c_str(), data.length());
    			req->res.status = 200;
    			req->res.reason = "OK";
    			h2o_start_response(req, &generator);
    			h2o_send(req, &body, 1, H2O_SEND_STATE_FINAL);
    		})
    		.fail([&req](std::exception_ptr err) {
    			try
    			{
    				std::rethrow_exception(err);
    			}
    			catch (std::exception const &e)
    			{
    				json error;
    				error["err"] = e.what();
    				vector<uint8_t> msgpack_response = json::to_msgpack(error);
    				string msgpack_string = string(msgpack_response.begin(), msgpack_response.end());
    
    				static h2o_generator_t generator = {NULL, NULL};
    				h2o_iovec_t body = h2o_strdup(&req->pool, msgpack_string.c_str(), msgpack_string.length());
    				req->res.status = 500;
    				req->res.reason = "ERROR";
    				h2o_start_response(req, &generator);
    				h2o_send(req, &body, 1, H2O_SEND_STATE_FINAL);
    			}
    		});
    	}
    
  • cti::promisify + ASIO = compilitation error

    cti::promisify + ASIO = compilitation error

    @Naios

    I am trying to use continuable along with non-boost ASIO library, my understanding about async, and template programming is not comparable with yours, and I haven't been successful up until now, so I have been fiddling with the examples but I get compiler error I haven't been able to solve.

    so in my class I have this members

    	asio::io_service mIoService;
    	asio::ip::udp::resolver mResolver;
    	asio::ip::tcp::socket mControlSocket;
    

    then I have been defining some methods, one of them almost copy-pasted from continuable documentation is this:

    	auto async_resolve(const asio::ip::udp::endpoint& endpoint)
    	{
    		return cti::promisify<asio::ip::udp::resolver::iterator>::with(
    		            [](auto&& promise, auto&& e, auto&&... args)
    		{
    			if (e) promise.set_exception(std::forward<decltype(e)>(e));
    			else promise.set_value(std::forward<decltype(args)>(args)...);
    		},
    		[&](auto&&... args)
    		{
    			mResolver.async_resolve(std::forward<decltype(args)>(args)...);
    		},
    		std::move(endpoint));
    	}
    

    but when I try to compile i get the following errors:

    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx: In constructor ‘TorProcess::TorProcess()’:
    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:205:24: warning: ‘TorProcess::mControlSocket’ will be initialized after [-Wreorder]
      asio::ip::tcp::socket mControlSocket;
                            ^~~~~~~~~~~~~~
    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:204:26: warning:   ‘asio::ip::udp::resolver TorProcess::mResolver’ [-Wreorder]
      asio::ip::udp::resolver mResolver;
                              ^~~~~~~~~
    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:54:2: warning:   when initialized here [-Wreorder]
      TorProcess():
      ^~~~~~~~~~
    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx: In instantiation of ‘TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)> [with auto:59 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >; auto:60 = const std::error_code&; auto:61 = {const asio::ip::basic_resolver_iterator<asio::ip::udp>&}]’:
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/other/promisify.hpp:81:31:   required from ‘cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)> mutable [with auto:55 = {const std::error_code&, const asio::ip::basic_resolver_iterator<asio::ip::udp>&}]’
    /usr/include/asio/detail/handler_type_requirements.hpp:107:9:   required by substitution of ‘template<class Handler, class Arg1, class Arg2> decltype (((sizeof ((Handler)(static_cast<const Handler&>(h))), h((* a1), (* a2))), (char)(0))) asio::detail::two_arg_handler_test(Handler, Arg1*, Arg2*) [with Handler = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>; Arg1 = const std::error_code; Arg2 = const asio::ip::basic_resolver_iterator<asio::ip::udp>]’
    /usr/include/asio/ip/basic_resolver.hpp:255:5:   required from ‘typename asio::async_result<typename asio::handler_type<ResolveHandler, void(std::error_code, asio::ip::basic_resolver_iterator<Protocol>)>::type>::type asio::ip::basic_resolver<InternetProtocol, ResolverService>::async_resolve(const endpoint_type&, ResolveHandler&&) [with ResolveHandler = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>; InternetProtocol = asio::ip::udp; ResolverService = asio::ip::resolver_service<asio::ip::udp>; typename asio::async_result<typename asio::handler_type<ResolveHandler, void(std::error_code, asio::ip::basic_resolver_iterator<Protocol>)>::type>::type = void; asio::ip::basic_resolver<InternetProtocol, ResolverService>::endpoint_type = asio::ip::basic_endpoint<asio::ip::udp>]’
    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:196:4:   required from ‘TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)> [with auto:62 = {const asio::ip::basic_endpoint<asio::ip::udp>, cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>}]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/utility/util.hpp:179:49:   required by substitution of ‘template<class Callable, class ... Args> constexpr decltype (forward<Callable>(callable)((forward<Args>)(cti::detail::util::invoke::args)...)) cti::detail::util::invoke(Callable&&, Args&& ...) [with Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>, cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>}]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/other/promisify.hpp:86:29:   [ skipping 8 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-base.hpp:174:7:   required from ‘cti::continuable_base<Data, Annotation>::~continuable_base() [with Data = cti::detail::base::proxy_continuable<cti::detail::identity<asio::ip::basic_resolver_iterator<asio::ip::udp> >, cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> >; Annotation = cti::detail::identity<asio::ip::basic_resolver_iterator<asio::ip::udp> >]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/core/base.hpp:167:58:   required from ‘static auto cti::detail::base::attorney::create_from(T&&, Hint, cti::detail::util::ownership) [with T = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)>; Hint = cti::detail::identity<asio::ip::basic_resolver_iterator<asio::ip::udp> >]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-base.hpp:851:45:   required from ‘constexpr auto cti::make_continuable(Continuation&&) [with Args = {asio::ip::basic_resolver_iterator<asio::ip::udp>}; Continuation = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)>]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/other/promisify.hpp:69:39:   required from ‘static auto cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-promisify.hpp:112:33:   required from ‘static auto cti::promisify<Result>::with(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]’
    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:198:22:   required from here
    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:191:11: error: no matching function for call to ‘cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >::set_exception(const std::error_code&)’
        if (e) promise.set_exception(std::forward<decltype(e)>(e));
               ^~~~~~~
    In file included from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/connection/connection-aggregated.hpp:39,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/connection/connection-all.hpp:41,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-base.hpp:40,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable.hpp:48,
                     from ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:31:
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/core/base.hpp:736:8: note: candidate: ‘void cti::detail::base::callbacks::final_callback<Args>::set_exception(cti::exception_t) [with Args = {asio::ip::basic_resolver_iterator<asio::ip::udp>}; cti::exception_t = std::error_condition]’
       void set_exception(exception_t exception) noexcept {
            ^~~~~~~~~~~~~
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/core/base.hpp:736:8: note:   no known conversion for argument 1 from ‘const std::error_code’ to ‘cti::exception_t’ {aka ‘std::error_condition’}
    In file included from /usr/include/asio/impl/io_service.hpp:18,
                     from /usr/include/asio/io_service.hpp:765,
                     from /usr/include/asio/basic_io_object.hpp:19,
                     from /usr/include/asio/basic_socket.hpp:20,
                     from /usr/include/asio/basic_datagram_socket.hpp:20,
                     from /usr/include/asio.hpp:19,
                     from ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:28:
    /usr/include/asio/ip/basic_resolver.hpp: In instantiation of ‘typename asio::async_result<typename asio::handler_type<ResolveHandler, void(std::error_code, asio::ip::basic_resolver_iterator<Protocol>)>::type>::type asio::ip::basic_resolver<InternetProtocol, ResolverService>::async_resolve(const endpoint_type&, ResolveHandler&&) [with ResolveHandler = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>; InternetProtocol = asio::ip::udp; ResolverService = asio::ip::resolver_service<asio::ip::udp>; typename asio::async_result<typename asio::handler_type<ResolveHandler, void(std::error_code, asio::ip::basic_resolver_iterator<Protocol>)>::type>::type = void; asio::ip::basic_resolver<InternetProtocol, ResolverService>::endpoint_type = asio::ip::basic_endpoint<asio::ip::udp>]’:
    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:196:4:   required from ‘TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)> [with auto:62 = {const asio::ip::basic_endpoint<asio::ip::udp>, cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>}]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/utility/util.hpp:179:49:   required by substitution of ‘template<class Callable, class ... Args> constexpr decltype (forward<Callable>(callable)((forward<Args>)(cti::detail::util::invoke::args)...)) cti::detail::util::invoke(Callable&&, Args&& ...) [with Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>, cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>}]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/other/promisify.hpp:86:29:   required from ‘cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/utility/traits.hpp:96:42:   required by substitution of ‘template<class U, class F, long unsigned int ...I> constexpr decltype (forward<U>(unpacker)((get<I>)((forward<F>)(cti::detail::traits::detail_unpack::unpack_impl::first_sequenceable))...)) cti::detail::traits::detail_unpack::unpack_impl(U&&, F&&, std::integer_sequence<long unsigned int, I ...>) [with U = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)>; F = std::tuple<TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp> >; long unsigned int ...I = {0, 1}]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/utility/traits.hpp:112:43:   required by substitution of ‘template<class Callable, class TupleLike, class Sequence> constexpr decltype (cti::detail::traits::detail_unpack::unpack_impl(forward<Callable>(obj), forward<TupleLike>(tuple_like), Sequence{})) cti::detail::traits::unpack(Callable&&, TupleLike&&) [with Callable = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)>; TupleLike = std::tuple<TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp> >; Sequence = std::integer_sequence<long unsigned int, 0, 1>]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/other/promisify.hpp:74:25:   [ skipping 5 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-base.hpp:174:7:   required from ‘cti::continuable_base<Data, Annotation>::~continuable_base() [with Data = cti::detail::base::proxy_continuable<cti::detail::identity<asio::ip::basic_resolver_iterator<asio::ip::udp> >, cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> >; Annotation = cti::detail::identity<asio::ip::basic_resolver_iterator<asio::ip::udp> >]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/core/base.hpp:167:58:   required from ‘static auto cti::detail::base::attorney::create_from(T&&, Hint, cti::detail::util::ownership) [with T = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)>; Hint = cti::detail::identity<asio::ip::basic_resolver_iterator<asio::ip::udp> >]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-base.hpp:851:45:   required from ‘constexpr auto cti::make_continuable(Continuation&&) [with Args = {asio::ip::basic_resolver_iterator<asio::ip::udp>}; Continuation = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)>]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/other/promisify.hpp:69:39:   required from ‘static auto cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-promisify.hpp:112:33:   required from ‘static auto cti::promisify<Result>::with(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]’
    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:198:22:   required from here
    /usr/include/asio/ip/basic_resolver.hpp:255:5: error: use of deleted function ‘cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>::<lambda>(const cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>&)’
         ASIO_RESOLVE_HANDLER_CHECK(
         ^~~~~~~~~~~~~~~~~~~~~~~~~~
    In file included from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-promisify.hpp:36,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable.hpp:54,
                     from ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:31:
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/other/promisify.hpp:78:22: note: ‘cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>::<lambda>(const cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>&)’ is implicitly deleted because the default definition would be ill-formed:
                     auto callback =
                          ^~~~~~~~
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/other/promisify.hpp:78:22: error: use of deleted function ‘cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >::final_callback(const cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >&)’
    In file included from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/connection/connection-aggregated.hpp:39,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/connection/connection-all.hpp:41,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-base.hpp:40,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable.hpp:48,
                     from ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:31:
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/core/base.hpp:707:8: note: ‘cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >::final_callback(const cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >&)’ is implicitly deleted because the default definition would be ill-formed:
     struct final_callback : util::non_copyable {
            ^~~~~~~~~~~~~~
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/core/base.hpp:707:8: error: use of deleted function ‘cti::detail::util::non_copyable::non_copyable(const cti::detail::util::non_copyable&)’
    In file included from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/utility/result-trait.hpp:39,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-result.hpp:38,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-base.hpp:39,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable.hpp:48,
                     from ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:31:
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/utility/util.hpp:209:3: note: declared here
       non_copyable(non_copyable const&) = delete;
       ^~~~~~~~~~~~
    In file included from /usr/include/asio/impl/io_service.hpp:18,
                     from /usr/include/asio/io_service.hpp:765,
                     from /usr/include/asio/basic_io_object.hpp:19,
                     from /usr/include/asio/basic_socket.hpp:20,
                     from /usr/include/asio/basic_datagram_socket.hpp:20,
                     from /usr/include/asio.hpp:19,
                     from ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:28:
    /usr/include/asio/detail/handler_type_requirements.hpp:111:8: note:   initializing argument 1 of ‘char (& asio::detail::two_arg_handler_test(Handler, ...))[2] [with Handler = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>]’
     char (&two_arg_handler_test(Handler, ...))[2];
            ^~~~~~~~~~~~~~~~~~~~
    /usr/include/asio/ip/basic_resolver.hpp:162:5: error: use of deleted function ‘cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>::<lambda>(const cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>&)’
         ASIO_RESOLVE_HANDLER_CHECK(
         ^~~~~~~~~~~~~~~~~~~~~~~~~~
    /usr/include/asio/detail/handler_type_requirements.hpp:126:28: note:   initializing argument 1 of ‘char asio::detail::argbyv(T) [with T = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>]’
     template <typename T> char argbyv(T);
                                ^~~~~~
    In file included from /usr/include/asio/ip/basic_resolver.hpp:25,
                     from /usr/include/asio.hpp:62,
                     from ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:28:
    /usr/include/asio/ip/resolver_service.hpp: At global scope:
    /usr/include/asio/ip/resolver_service.hpp:142:3: error: ‘typename asio::async_result<typename asio::handler_type<ResolveHandler, void(std::error_code, asio::ip::basic_resolver_iterator<Protocol>)>::type>::type asio::ip::resolver_service<InternetProtocol>::async_resolve(asio::ip::resolver_service<InternetProtocol>::implementation_type&, const endpoint_type&, ResolveHandler&&) [with ResolveHandler = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>; InternetProtocol = asio::ip::udp; typename asio::async_result<typename asio::handler_type<ResolveHandler, void(std::error_code, asio::ip::basic_resolver_iterator<Protocol>)>::type>::type = void; asio::ip::resolver_service<InternetProtocol>::implementation_type = std::shared_ptr<void>; asio::ip::resolver_service<InternetProtocol>::endpoint_type = asio::ip::basic_endpoint<asio::ip::udp>]’, declared using local type ‘cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::async_resolve(const endpoint&)::<lambda(auto:59&&, auto:60&&, auto:61&& ...)>; Callable = TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::udp>}; Result = {asio::ip::basic_resolver_iterator<asio::ip::udp>}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<asio::ip::basic_resolver_iterator<asio::ip::udp> >]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::async_resolve(const endpoint&)::<lambda(auto:62&& ...)>, const asio::ip::basic_endpoint<asio::ip::udp>}]::<lambda(auto:55&& ...)>’, is used but never defined [-fpermissive]
       async_resolve(implementation_type& impl, const endpoint_type& endpoint,
       ^~~~~~~~~~~~~
    cc1plus: warning: unrecognized command line option ‘-Wno-inconsistent-missing-override’
    make[1]: Leaving directory '/home/gio/Builds/RetroShare-Desktop-Debug/libretroshare/src'
    make[1]: *** [Makefile.libretroshare:13825: temp/linux-g++/obj/tortransport.o] Error 1
    make: *** [Makefile:128: sub-libretroshare-src-libretroshare-pro-make_first] Error 2
    16:42:49: The process "/usr/bin/make" exited with code 2.
    Error while building/deploying project RetroShare (kit: Desktop)
    When executing step "Make"
    16:42:49: Elapsed time: 00:03.
    

    While trying to understand were the error came from I have been fiddling with other methods, but with each of them I have been getting similar errors, I attach those method definitions + compile errors here for completeness

    	auto connect(const asio::ip::tcp::endpoint& endpoint)
    	{
    		return cti::promisify<void>::with(
    		[](auto&& promise, const asio::error_code& e)
    		{
    			if(e) promise.set_exception(cti::exception_t(e.value(), e.category()));
    			else promise.set_value();
    		},
    		[this](auto&&... args)
    		{
    			mControlSocket.async_connect(std::forward<decltype(args)>(args)...);
    		},
    		std::move(endpoint) );
    
    		//return mControlSocket.async_connect(endpoint,[](asio::error_code){});
    	}
    

    compile errors:

    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx: In constructor ‘TorProcess::TorProcess()’:
    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:206:24: warning: ‘TorProcess::mControlSocket’ will be initialized after [-Wreorder]
      asio::ip::tcp::socket mControlSocket;
                            ^~~~~~~~~~~~~~
    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:205:26: warning:   ‘asio::ip::udp::resolver TorProcess::mResolver’ [-Wreorder]
      asio::ip::udp::resolver mResolver;
                              ^~~~~~~~~
    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:54:2: warning:   when initialized here [-Wreorder]
      TorProcess():
      ^~~~~~~~~~
    In file included from /usr/include/asio/impl/io_service.hpp:18,
                     from /usr/include/asio/io_service.hpp:765,
                     from /usr/include/asio/basic_io_object.hpp:19,
                     from /usr/include/asio/basic_socket.hpp:20,
                     from /usr/include/asio/basic_datagram_socket.hpp:20,
                     from /usr/include/asio.hpp:19,
                     from ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:28:
    /usr/include/asio/basic_socket.hpp: In instantiation of ‘typename asio::async_result<typename asio::handler_type<ConnectHandler, void(std::error_code)>::type>::type asio::basic_socket<Protocol, SocketService>::async_connect(const endpoint_type&, ConnectHandler&&) [with ConnectHandler = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>; Protocol = asio::ip::tcp; SocketService = asio::stream_socket_service<asio::ip::tcp>; typename asio::async_result<typename asio::handler_type<ConnectHandler, void(std::error_code)>::type>::type = void; asio::basic_socket<Protocol, SocketService>::endpoint_type = asio::ip::basic_endpoint<asio::ip::tcp>]’:
    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:179:4:   required from ‘TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)> [with auto:60 = {const asio::ip::basic_endpoint<asio::ip::tcp>, cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>}]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/utility/util.hpp:179:49:   required by substitution of ‘template<class Callable, class ... Args> constexpr decltype (forward<Callable>(callable)((forward<Args>)(cti::detail::util::invoke::args)...)) cti::detail::util::invoke(Callable&&, Args&& ...) [with Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>, cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>}]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/other/promisify.hpp:86:29:   required from ‘cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/utility/traits.hpp:96:42:   required by substitution of ‘template<class U, class F, long unsigned int ...I> constexpr decltype (forward<U>(unpacker)((get<I>)((forward<F>)(cti::detail::traits::detail_unpack::unpack_impl::first_sequenceable))...)) cti::detail::traits::detail_unpack::unpack_impl(U&&, F&&, std::integer_sequence<long unsigned int, I ...>) [with U = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)>; F = std::tuple<TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp> >; long unsigned int ...I = {0, 1}]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/utility/traits.hpp:112:43:   required by substitution of ‘template<class Callable, class TupleLike, class Sequence> constexpr decltype (cti::detail::traits::detail_unpack::unpack_impl(forward<Callable>(obj), forward<TupleLike>(tuple_like), Sequence{})) cti::detail::traits::unpack(Callable&&, TupleLike&&) [with Callable = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)>; TupleLike = std::tuple<TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp> >; Sequence = std::integer_sequence<long unsigned int, 0, 1>]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/other/promisify.hpp:74:25:   [ skipping 5 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-base.hpp:174:7:   required from ‘cti::continuable_base<Data, Annotation>::~continuable_base() [with Data = cti::detail::base::proxy_continuable<cti::detail::identity<>, cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> >; Annotation = cti::detail::identity<>]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/core/base.hpp:167:58:   required from ‘static auto cti::detail::base::attorney::create_from(T&&, Hint, cti::detail::util::ownership) [with T = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)>; Hint = cti::detail::identity<>]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-base.hpp:851:45:   required from ‘constexpr auto cti::make_continuable(Continuation&&) [with Args = {void}; Continuation = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)>]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/other/promisify.hpp:69:39:   required from ‘static auto cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]’
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-promisify.hpp:112:33:   required from ‘static auto cti::promisify<Result>::with(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]’
    ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:181:23:   required from here
    /usr/include/asio/basic_socket.hpp:754:5: error: use of deleted function ‘cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>::<lambda>(const cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>&)’
         ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check;
         ^~~~~~~~~~~~~~~~~~~~~~~~~~
    In file included from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-promisify.hpp:36,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable.hpp:54,
                     from ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:31:
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/other/promisify.hpp:78:22: note: ‘cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>::<lambda>(const cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>&)’ is implicitly deleted because the default definition would be ill-formed:
                     auto callback =
                          ^~~~~~~~
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/other/promisify.hpp:78:22: error: use of deleted function ‘cti::detail::base::callbacks::final_callback<>::final_callback(const cti::detail::base::callbacks::final_callback<>&)’
    In file included from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/connection/connection-aggregated.hpp:39,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/connection/connection-all.hpp:41,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-base.hpp:40,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable.hpp:48,
                     from ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:31:
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/core/base.hpp:707:8: note: ‘cti::detail::base::callbacks::final_callback<>::final_callback(const cti::detail::base::callbacks::final_callback<>&)’ is implicitly deleted because the default definition would be ill-formed:
     struct final_callback : util::non_copyable {
            ^~~~~~~~~~~~~~
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/core/base.hpp:707:8: error: use of deleted function ‘cti::detail::util::non_copyable::non_copyable(const cti::detail::util::non_copyable&)’
    In file included from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/utility/result-trait.hpp:39,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-result.hpp:38,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable-base.hpp:39,
                     from ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/continuable.hpp:48,
                     from ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:31:
    ../../../../Development/rs-develop/supportlibs/continuable/include/continuable/detail/utility/util.hpp:209:3: note: declared here
       non_copyable(non_copyable const&) = delete;
       ^~~~~~~~~~~~
    In file included from /usr/include/asio/impl/io_service.hpp:18,
                     from /usr/include/asio/io_service.hpp:765,
                     from /usr/include/asio/basic_io_object.hpp:19,
                     from /usr/include/asio/basic_socket.hpp:20,
                     from /usr/include/asio/basic_datagram_socket.hpp:20,
                     from /usr/include/asio.hpp:19,
                     from ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:28:
    /usr/include/asio/detail/handler_type_requirements.hpp:101:8: note:   initializing argument 1 of ‘char (& asio::detail::one_arg_handler_test(Handler, ...))[2] [with Handler = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>]’
     char (&one_arg_handler_test(Handler h, ...))[2];
            ^~~~~~~~~~~~~~~~~~~~
    /usr/include/asio/basic_socket.hpp:754:5: error: use of deleted function ‘cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>::<lambda>(const cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>&)’
         ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check;
         ^~~~~~~~~~~~~~~~~~~~~~~~~~
    /usr/include/asio/detail/handler_type_requirements.hpp:126:28: note:   initializing argument 1 of ‘char asio::detail::argbyv(T) [with T = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>]’
     template <typename T> char argbyv(T);
                                ^~~~~~
    In file included from /usr/include/asio.hpp:18,
                     from ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:28:
    /usr/include/asio/async_result.hpp: At global scope:
    /usr/include/asio/async_result.hpp:59:12: error: ‘asio::detail::async_result_init<Handler, Signature>::async_result_init(Handler&&) [with Handler = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>; Signature = void(std::error_code)]’, declared using local type ‘cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>’, is used but never defined [-fpermissive]
       explicit async_result_init(ASIO_MOVE_ARG(Handler) orig_handler)
                ^~~~~~~~~~~~~~~~~
    In file included from /usr/include/asio/detail/wrapped_handler.hpp:18,
                     from /usr/include/asio/io_service.hpp:24,
                     from /usr/include/asio/basic_io_object.hpp:19,
                     from /usr/include/asio/basic_socket.hpp:20,
                     from /usr/include/asio/basic_datagram_socket.hpp:20,
                     from /usr/include/asio.hpp:19,
                     from ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:28:
    /usr/include/asio/detail/bind_handler.hpp:100:31: error: ‘asio::detail::binder1<Handler, Arg1> asio::detail::bind_handler(Handler, const Arg1&) [with Handler = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>; Arg1 = std::error_code]’, declared using local type ‘cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>’, is used but never defined [-fpermissive]
     inline binder1<Handler, Arg1> bind_handler(Handler handler,
                                   ^~~~~~~~~~~~
    In file included from /usr/include/asio/basic_socket_streambuf.hpp:28,
                     from /usr/include/asio/basic_socket_iostream.hpp:24,
                     from /usr/include/asio.hpp:27,
                     from ../../../../Development/rs-develop/libretroshare/src/pluggabletransports/tortransport.cxx:28:
    /usr/include/asio/stream_socket_service.hpp:223:3: error: ‘typename asio::async_result<typename asio::handler_type<ConnectHandler, void(std::error_code)>::type>::type asio::stream_socket_service<Protocol>::async_connect(asio::stream_socket_service<Protocol>::implementation_type&, const endpoint_type&, ConnectHandler&&) [with ConnectHandler = cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>; Protocol = asio::ip::tcp; typename asio::async_result<typename asio::handler_type<ConnectHandler, void(std::error_code)>::type>::type = void; asio::stream_socket_service<Protocol>::implementation_type = asio::detail::reactive_socket_service<asio::ip::tcp>::implementation_type; asio::stream_socket_service<Protocol>::endpoint_type = asio::ip::basic_endpoint<asio::ip::tcp>]’, declared using local type ‘cti::detail::convert::promisify_helper<Result>::from(Resolver&&, Callable&&, Args&& ...) [with Resolver = TorProcess::connect(const endpoint&)::<lambda(auto:59&&, const error_code&)>; Callable = TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>; Args = {const asio::ip::basic_endpoint<asio::ip::tcp>}; Result = {void}]::<lambda(auto:53&&)> mutable [with auto:53 = cti::detail::base::callbacks::final_callback<>]::<lambda(auto:54&& ...)> mutable [with auto:54 = {TorProcess::connect(const endpoint&)::<lambda(auto:60&& ...)>, const asio::ip::basic_endpoint<asio::ip::tcp>}]::<lambda(auto:55&& ...)>’, is used but never defined [-fpermissive]
       async_connect(implementation_type& impl,
       ^~~~~~~~~~~~~
    cc1plus: warning: unrecognized command line option ‘-Wno-inconsistent-missing-override’
    make[1]: Leaving directory '/home/gio/Builds/RetroShare-Desktop-Debug/libretroshare/src'
    make[1]: *** [Makefile.libretroshare:13825: temp/linux-g++/obj/tortransport.o] Error 1
    make: *** [Makefile:128: sub-libretroshare-src-libretroshare-pro-make_first] Error 2
    16:47:44: The process "/usr/bin/make" exited with code 2.
    Error while building/deploying project RetroShare (kit: Desktop)
    When executing step "Make"
    16:47:44: Elapsed time: 00:03.
    

    In this latter case ASIO apparently complain of the callback type not being the expected one. The compiler I am using is GCC 8.3.0

    Thanks for sharing this library and for the help!

  • Possible data race involving set_promise() & sys::transforms::wait()

    Possible data race involving set_promise() & sys::transforms::wait()

    @Naios

    Almost every time I run the program it will hang in the .apply(cti::transforms::wait()). Thread sanitizer also detects and reports a data race.

    The compile command is in the README. continuable-bug.tar.gz


    Commit Hash

    Latest.

    Expected Behavior

    Execute the loop 20000 times.

    Actual Behavior

    Misses a wakeup from the set_promise() call.

    Steps to Reproduce

    compile and execute the program. A thread sanitizer report will appear.

    You may want to comment out line 41 in main.cc

    Your Environment

    • OS: Windows Subsystem for Linux kernel. "uname -r" gives: 4.19.128-microsoft-standard
    • Compiler and version: g++10
    • Standard library (if non default):
  • question: is_continuation<> and asio::strand::post

    question: is_continuation<> and asio::strand::post

    I have some existing code that posts synchronous methods to a boost strand in order to queue their execution on a thread pool. However, in order to reduce the number of waiting threads, i'd like to convert these methods to continuable-returning coroutines. I have all the asio i/o calls asyncronized via cti::use_continuable, but what I'm trying to work out is whether or not posting a coroutine to a strand will still serialize the invocation of those asynchronous methods? I notice there's a specialization of is_continuation in erasure.hpp, is that related somehow?

    i'm using continuable 4.1.0 & boost 1.77, if that's important.

  • How to get error code when using use_continuable with asio

    How to get error code when using use_continuable with asio

    @Naios

    Commit Hash

    61826817c7716cec5e476a68f679d9347891bba7

    Expected Behavior

    std::exception_ptr parameter to .fail() captures the error when using use_continuable with boost asio

    Actual Behavior

    The std::exception_ptr is null.

    Steps to Reproduce

    #include <boost/asio.hpp>
    #include <boost/asio/steady_timer.hpp>
    #include <iostream>
    #include <iomanip>
    #include <chrono>
    #include <memory>
    
    #include <continuable/continuable.hpp>
    #include <continuable/external/asio.hpp>
    
    namespace asio = boost::asio;
    namespace sys = boost::system;
    
    int main()
    {
        asio::io_service io;
    
        auto time = std::chrono::seconds{1};
        asio::steady_timer timer{io, time};
    
        timer.async_wait(cti::use_continuable)
            .then([time]() {
                std::cout << time.count() << " s elapsed\n"; })
            .fail([](std::exception_ptr pe) {
                // !!!! Here I expect pe to point to operation_aborted !!!!
                std::cerr << "fail! pe: " << std::boolalpha << (bool)pe << '\n';
                if(!pe) return;
                try{std::rethrow_exception(pe);}
                catch(std::exception &e){std::cerr << e.what();}
                catch(...) {std::cerr << "something else";}});
    
    
        // This function forces the completion of any pending asynchronous wait
        // operations against the timer.
        // The handler for each cancelled operation will be invoked with the
        // boost::asio::error::operation_aborted error code.
        timer.cancel();
    
        io.run();
    }
    

    Output: fail! pe: false

    Your Environment

    • OS: Linux (Ubuntu focal)
    • Compiler and version: clang version 10.0.0-1ubuntu2
    • Standard library (if non default): boost 1.71.0 from ubuntu package repo
  • Hi, How to span one coroutine ?

    Hi, How to span one coroutine ?

    @Naios


    Commit Hash

    {Please write here}

    Expected Behavior

    {Please write here}

    Actual Behavior

    {Please write here}

    Steps to Reproduce

    {Please write here}

    Your Environment

    • OS: {Please write here - Windows/Linux dist/OSX}
    • Compiler and version: {Please write here - MSVC/Clang/GCC/Other}
    • Standard library (if non default): {Please write here}
  • unit-test/test-continuable-single fails on gcc 8.2

    unit-test/test-continuable-single fails on gcc 8.2

    @Naios

    unit-test/test-continuable-single results in segmentation fault on gcc 8.2 Also tested with clang++ 7.0 and it passes, and it looks like gcc6 on Travis also passes thus I am not sure if it is a compiler regression or something like an undefined behavior (I will update the post after testing with gcc-trunk)

    Output of running the tests (successfull tests are ommitted):

    ../test/unit-test/single/test-continuable-flat-variant.cpp:70: Failure Expected equality of these values: e.cast() Which is: 4790218 CANARY Which is: 373671 ../test/unit-test/single/test-continuable-flat-variant.cpp:78: Failure Value of: e.is() Actual: false Expected: true [ FAILED ] flat_variant_single_test.is_copy_constructible (0 ms)

    ../test/unit-test/single/test-continuable-flat-variant.cpp:121: Failure Value of: variant.template is() Actual: false Expected: true ../test/unit-test/single/test-continuable-flat-variant.cpp:121: Failure Value of: variant.template is() Actual: false Expected: true ../test/unit-test/single/test-continuable-flat-variant.cpp:121: Failure Value of: variant.template is() Actual: false Expected: true ../test/unit-test/single/test-continuable-flat-variant.cpp:121: Failure Value of: variant.template is() Actual: false Expected: true ../test/unit-test/single/test-continuable-flat-variant.cpp:121: Failure Value of: variant.template is() Actual: false Expected: true ../test/unit-test/single/test-continuable-flat-variant.cpp:160: Failure Value of: destroyed Actual: false Expected: true [ FAILED ] flat_variant_single_test.test_leak_regression (1 ms)

    ../test/unit-test/single/test-continuable-result.cpp:152: Failure Value of: bool(e) Actual: false Expected: true ../test/unit-test/single/test-continuable-result.cpp:153: Failure Expected equality of these values: *e Which is: 11712264 CANARY Which is: 373671 ../test/unit-test/single/test-continuable-result.cpp:154: Failure Value of: e.is_value() Actual: false Expected: true

    I also got several warnings on uninitialized variables but I am not sure if they are intentional or bugs.

    ../include/continuable/detail/utility/flat-variant.hpp:369:23: warning: ‘((void)+16)’ may be used uninitialized in this function [-Wmaybe-uninitialized]

    ../include/continuable/detail/utility/traits.hpp:99:35: warning: ‘((void)+8)’ may be used uninitialized in this function [-Wmaybe-uninitialized]

    There should be a few more like these I can add those as well


    Commit Hash

    e23e363

    Expected Behavior

    Tests should pass

    Actual Behavior

    Some of the tests fail and program finishes with segmentation fault

    Steps to Reproduce

    cmake -G Ninja -DCMAKE_BUILD_TYPE=Release .. ninja test

    Your Environment

    • OS: Fedora 28
    • Compiler and version: GCC8.2
    • Standard library (if non default): Default
  • Missing failure chaining support

    Missing failure chaining support

    @Naios


    To better support my asynchronous operations, I would like to create a wrapper on my asynchronous chain to release a mutex regardless of the outcome of the chain, for example;

    do_stuff().then(/* ... */).next(invariant_unlock<int>{M_mut});
    

    To accomplish this, I wrote a supporting type invariant_unlock which looks similar to:

    template <typename... Ret_Ts> struct invariant_unlock
    {
    	explicit invariant_unlock(std::mutex& mutex) : M_mutex(mutex)
    	{
    	}
    	template <typename... Ts> auto operator()(Ts&&... ts)
    	{
    		M_mutex.unlock();
    		return std::make_tuple<Ts...>(std::forward<Ts>(ts)...);
    	}
    	auto operator()(cti::dispatch_error_tag, std::exception_ptr e_ptr)
    	{
    		M_mutex.unlock();
    		return cti::make_exceptional_continuable<Ret_Ts...>(std::move(e_ptr));
    	}
      private:
    	std::mutex& M_mutex;
    };
    

    Unfortunately, using the class doesn't work, in fact I can't figure out how to chain together failure clauses at all:

    auto test() {
        return cti::make_continuable<int>([](auto&& promise) { promise.set_value(5); });
    }
    int main() {
        test()
            .then([]() { throw std::runtime_error("a"); })
            .fail([](std::exception_ptr) { throw std::runtime_error("b"); })
            .fail([](std::exception_ptr) { std::cout<<"Ex2\n"; });
    }
    

    I never reach the second failure block, in fact the program is aborted.

    I found a relative snippet from the documentation which states: Multiple handlers are allowed to be registered, however the asynchronous call hierarchy is aborted after the first called fail handler and only the closest handler below is called. Which (to me) states that the behaviour is completely expected and defined.


    If it's not possible to pass a failure down the chain, I believe it would be useful as it would allow me to wrap my chain with new functionality without consuming any errors.

    Thanks

  • cancellation/abortion feature support

    cancellation/abortion feature support

    I am digging into the library more and more and really appreciate and enjoy it! One feature which is missing now is that how to cancel the chained pipeline. Inside the pipeline (both in the promise callback and corresponding then-result-handler) we can call promise.set_exception or return cancel() to terminate the chained pipeline or stop() it which is really good. How to abort or cancel from outside? i.e. in my app, I want to abort the pipeline or kill it during the shutdown, I want to quit as soon as possible. Since continuable is preferred R-value, once we let the chained pipeline run, we have no reference or control over it. My current solution is to pass a lambda (i.e. abortion/cancellation checker) in the callback and then-handlers, if it returns true, we will call cti::cancel(). However, the downside of this solution is that you have to call and check it in every handler and promise callback.

    1. Is there any plan or future support for passing this kinda abort/cancellation checker into the framework? then we do not need to proactively check it everywhere.
    2. Even better, we can pass in a cancellation/timeout/deadline context as context.Context in golang with support like below:
    ctx, cancel := context.withContext(backgroundContext)
    // later we can call `cancel` function to drop the whole pipeline. 
    // timeout/deadline are just fancy interface to call this `cancel()` by the timer.
    
  • Customized error type

    Customized error type

    First I really enjoy this great library and really nice work! It does solve the callback hell with asio. Since we have no coroutine available whatsoever, continuable probably is now the best we can achieve.

    1. Regarding the customized error, i.e. cti::exception_t.
     void operator()(exception_arg_t, exception_t exception) && {
        // Only handle the exception when it is present, otherwise handle it as
        // a cancellation of the control flow.
        // This behaviour is intentionally correct for
        // - `std::exception_ptr`
        // - `std::error_code`
        // - `std::error_condition`
        // which allow to be default constructed and then return false
        // by their corresponding `operator bool()`.
        if (bool(exception)) {
    

    In the callback's excetion_t has to implement operator bool which is not so portable and could be confusing,e.g. absl::Status or our own Error. in absl::Status, it prefers to check by absl::Status::ok(), however, bool(exception) should mean a non-zero error code, i.e. not ok, which we do not want to add an operator bool for absl::Status or our own error type.

    I am suggesting if we could provide a functor to replace bool(exception), i.e. something similar to std::hash, then we could implement it for the given error type.

    1. Since there is only one definition of cti::exception_t, if we decide to go with our own or google's absl::Status, then the asio's integration will be a problem where only exception_ptr and error_condition are supported. Somehow, we need to map the error_condition into our own error type, e.g. map e.Value() + e.Category() into absl::Status. Then we need to change the continuable's source code? What is the best pattern to deal with it? Is there any considerable support in the future for your library? I know it is probably out of the scope of this library. I am really interested in this library and really would like to use it for our project. Possible solution in the external/asio.hpp:
    promise.set_exception(exception_t(e.value(), e.category()));
    

    How about template specialization for a different type of exception_t? we can default to std::error_condtion. Then we got a chance to specialize an exception_t on our own, e.g. make_error(e). It would look like:

    promise.set_exception(make_error(e));
    
  • g++ 9/10 compile error on std::variant<cti::work>

    g++ 9/10 compile error on std::variant

    @Naios

    This concerns g++ 9.3.0 and 10.0.1

    Using cti::work within a variant leads to a compiler error in "struct assert_wrong_copy_assign" in function2.hpp.

    Using std::is_copy_constructible_v makes the compiler happy.


    Commit Hash

    Latest

    Expected Behavior

    No compiler error

    Actual Behavior

    I get this error from g++-9:

    /root/.conan/data/function2/4.1.0///package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/function2/function2.hpp:1398:60: error: incomplete type 'std::is_copy_constructible<cti::promise_base<fu2::abi_400::detail::function<fu2::abi_400::detail::config<true, false, fu2::capacity_fixed<32> >, fu2::abi_400::detail::property<true, false, void() &&, void(cti::exception_arg_t, std::__exception_ptr::exception_ptr) &&> >, cti::detail::identity<> > >' used in nested name specifier 1398 | static_assert(!Config::is_owning || !Config::is_copyable || | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~ 1399 | std::is_copy_constructible<std::decay_t>::value, | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Steps to Reproduce

    compile with g++-9 or 10 a source file with the following content (could not attach):

    #include <continuable/continuable.hpp>
    #include <variant>
    void foo() { std::variant<cti::work> t; }
    

    Your Environment

    • OS: debian bullseye/sid
    • Compiler and version: G++ 9.3.0, 10.0.1
    • Standard library (if non default): {Please write here}
  • Conan not found in remote-center

    Conan not found in remote-center

    @Naios

    Conan fails to find the continuable package in conan-center.


    Commit Hash

    Don't understand what to write here...

    Expected Behavior

    The following command should find continuable in the central repository:

    conan search continuable --remote=conan-center

    Actual Behavior

    Steps to Reproduce

    Make sure Conan is installed, then run:

    conan search continuable --remote=conan-center
    There are no packages matching the 'continuable' pattern
    

    Your Environment

    • OS: OSX
    • Compiler and version: Apple clang version 11.0.0 (clang-1100.0.33.17)
    • Standard library (if non default): {Please write here}
  • Reusable continuation chains

    Reusable continuation chains

    Thanks for this fantastic library @Naios. The amount of work you must have put into the documentation is really appreciated.

    I'm wondering whether reusable continuation chains are a planned feature, or indeed whether your implementation even permits such a thing? If it is possible, could you please give a brief summary of what would need to be done/how it should be approached? I'd be interested in implementing such a thing and would appreciate your thoughts.

Modern concurrency for C++. Tasks, executors, timers and C++20 coroutines to rule them all

concurrencpp, the C++ concurrency library concurrencpp is a tasking library for C++ allowing developers to write highly concurrent applications easily

Aug 10, 2022
Open source PHP extension for Async IO, Coroutines and Fibers

Swoole is an event-driven asynchronous & coroutine-based concurrency networking communication engine with high performance written in C++ for PHP. Ope

Aug 18, 2022
C++20 coroutines-based cooperative multitasking library

?? Coop Coop is a C++20 coroutines-based library to support cooperative multitasking in the context of a multithreaded application. The syntax will be

Aug 11, 2022
Discrete-event simulation in C++20 using coroutines

SimCpp20 SimCpp20 is a discrete-event simulation framework for C++20. It is similar to SimPy and aims to be easy to set up and use. Processes are defi

Apr 29, 2022
Header-Only C++20 Coroutines library

CPP20Coroutines Header-Only C++20 Coroutines library This repository aims to demonstrate the capabilities of C++20 coroutines. generator Generates val

Mar 2, 2022
Cppcoro - A library of C++ coroutine abstractions for the coroutines TS

CppCoro - A coroutine library for C++ The 'cppcoro' library provides a large set of general-purpose primitives for making use of the coroutines TS pro

Aug 14, 2022
Coro - Single-header library facilities for C++2a Coroutines

coro This is a collection of single-header library facilities for C++2a Coroutines. coro/include/ co_future.h Provides co_future<T>, which is like std

Jul 20, 2022
Elle - The Elle coroutine-based asynchronous C++ development framework.
Elle - The Elle coroutine-based asynchronous C++ development framework.

Elle, the coroutine-based asynchronous C++ development framework Elle is a collection of libraries, written in modern C++ (C++14). It contains a rich

Jul 29, 2022
Aug 17, 2022
An implementation of Actor, Publish-Subscribe, and CSP models in one rather small C++ framework. With performance, quality, and stability proved by years in the production.
An implementation of Actor, Publish-Subscribe, and CSP models in one rather small C++ framework. With performance, quality, and stability proved by years in the production.

What is SObjectizer? What distinguishes SObjectizer? SObjectizer is not like TBB, taskflow or HPX Show me the code! HelloWorld example Ping-Pong examp

Aug 11, 2022
Simple and fast C library implementing a thread-safe API to manage hash-tables, linked lists, lock-free ring buffers and queues

libhl C library implementing a set of APIs to efficiently manage some basic data structures such as : hashtables, linked lists, queues, trees, ringbuf

Jul 30, 2022
Sqrt OS is a simulation of an OS scheduler and memory manager using different scheduling algorithms including Highest Priority First (non-preemptive), Shortest Remaining Time Next, and Round Robin
Sqrt OS is a simulation of an OS scheduler and memory manager using different scheduling algorithms including Highest Priority First (non-preemptive), Shortest Remaining Time Next, and Round Robin

A CPU scheduler determines an order for the execution of its scheduled processes; it decides which process will run according to a certain data structure that keeps track of the processes in the system and their status.

Jul 14, 2021
RocketOS is a Unix based OS that uses legacy BIOS and GRUB and is written in C17. It is being developed for educational purposes primarily, but it still is a serious project. It is currently in its infancy.

RocketOS What is RocketOS? RocketOS is a Unix based OS that uses legacy BIOS and GRUB and is written in C17. It is being developed for educational pur

Jul 17, 2022
Nov 24, 2021
OOX: Out-of-Order Executor library. Yet another approach to efficient and scalable tasking API and task scheduling.

OOX Out-of-Order Executor library. Yet another approach to efficient and scalable tasking API and task scheduling. Try it Requirements: Install cmake,

Aug 9, 2022
Parallel-hashmap - A family of header-only, very fast and memory-friendly hashmap and btree containers.
Parallel-hashmap - A family of header-only, very fast and memory-friendly hashmap and btree containers.

The Parallel Hashmap Overview This repository aims to provide a set of excellent hash map implementations, as well as a btree alternative to std::map

Aug 9, 2022
Bolt is a C++ template library optimized for GPUs. Bolt provides high-performance library implementations for common algorithms such as scan, reduce, transform, and sort.

Bolt is a C++ template library optimized for heterogeneous computing. Bolt is designed to provide high-performance library implementations for common

Jun 27, 2022
A General-purpose Parallel and Heterogeneous Task Programming System
A General-purpose Parallel and Heterogeneous Task Programming System

Taskflow Taskflow helps you quickly write parallel and heterogeneous tasks programs in modern C++ Why Taskflow? Taskflow is faster, more expressive, a

Aug 16, 2022