Giter Club home page Giter Club logo

continuable's People

Contributors

cstratopoulos avatar hatefulmoron avatar naios avatar piersh-aetheros avatar rkonklewski-am2m avatar rogiel avatar stabishazam avatar warchant avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

continuable's Issues

g++ 9/10 compile error on std::variant<cti::work>

@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}

ToDo & Ideas

  • Continuable::operator&& to support "and" chaining.
  • Continuable::operator|| to support "or" chaining.
  • Continuable<>::toFuture()
  • Parameter pass through with evaluation.
  • Fail handler (exceptions & error codes)
  • Options to define strategies

Confusing error regarding `result` from VC++ when making a continuable from a lambda that captures a variable called `result`

@Naios

Using Continuable 4.1.0

Reproduction steps:

  1. Launch Visual Studio 2019 native tools command prompt
  2. Create folder somewhere and switch to it
    mkdir C:\temp\bug55
    cd /d C:\temp\bug55
    
  3. Change to folder and clone Continuable
    git clone --recursive https://github.com/naios/continuable
    
  4. Create test.cpp with the following contents (e.g., via copy con test.cpp)
    #include <continuable/continuable.hpp>
    static void Test() {
        int result = 0;
        cti::make_continuable<int>([result](auto&& promise) {});
    }
    
  5. Compile
    cl /I .\continuable\include test.cpp /I .\continuable\dep\function2\function2\include
    

Note probably-unexpected error...

Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30146 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

test.cpp
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\include\ppltasks.h(1571): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
.\continuable\include\continuable/detail/core/base.hpp(143): error C2327: 'Test::<lambda_ce49853aebba6891891f5a54e1664ea4>::result': is not a type name, static, or enumerator
.\continuable\include\continuable/detail/core/base.hpp(168): note: see reference to class template instantiation 'cti::detail::base::proxy_continuable<hint_t,Test::<lambda_ce49853aebba6891891f5a54e1664ea4>>' being compiled
.\continuable\include\continuable/continuable-base.hpp(898): note: see reference to function template instantiation 'auto cti::detail::base::attorney::create_from<_Ty,cti::detail::identity<int>>(T &&,Hint,cti::detail::util::ownership)' being compiled
        with
        [
            _Ty=Test::<lambda_ce49853aebba6891891f5a54e1664ea4>,
            T=Test::<lambda_ce49853aebba6891891f5a54e1664ea4>,
            Hint=cti::detail::identity<int>
        ]
test.cpp(4): note: see reference to function template instantiation 'auto cti::make_continuable<int,Test::<lambda_ce49853aebba6891891f5a54e1664ea4>>(Continuation &&)' being compiled
        with
        [
            Continuation=Test::<lambda_ce49853aebba6891891f5a54e1664ea4>
        ]

In the end I tracked this down to captured variables in msvc apparently giving their lambda's type member variables of the same name. So result is a member variable on the base class for proxy_continuable in this case.

This feels like a msvc problem - looks like clang and gcc must rename the captured variables, or use some other mechanism? - but perhaps it's fixable. I'm afraid I stopped at C++14 so I have no specific suggestions. Maybe a note in the documentation would suffice.

Compiler Explorer example that I think narrows it down to the issue: https://godbolt.org/z/7qz4sd7sT

Thanks,

--Tom

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

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

Trigger failure within continuation without using exceptions

Hi @Naios,

I'd like to use this library in a project where we don't use exceptions.
I can of course set an error using a promise, but is it somehow possible
to have error logic in a normal continuable, like so:

do_stuff().then([](int result) {
    if (result < 0) return cancel();
    return 2*result;
});

Or is there maybe some other pattern I could use?

Thank you very much for all your work!

tutorial code does not compile

@Naios

this code from "Connecting continuables" dosnt compile under Visual studio 2019. error is "attempting to reference a deleted function". I think you are missing a std::move() when calling cti::when_all()

// cti::populate just creates a std::vector from the two continuables.
auto v = cti::populate(cti::make_ready_continuable(0),
cti::make_ready_continuable(1));

for (int i = 2; i < 5; ++i) {
// It is possible to add more continuables
// to the container afterwards
container.emplace_back(cti::make_ready_continuable(i));
}

cti::when_all(v)
.then([](std::vector resolved) {
// ...
});


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}

CMake files refer to CMAKE_SOURCE_DIR

@Naios


Changing the references inside cmake/configure_macros.cmake and cmake/configure_compiler.cmake from referencing ${CMAKE_SOURCE_DIR} to ${PROJECT_SOURCE_DIR} solves this issue for me.

CMAKE_SOURCE_DIR points to the parent project (my project), whereas PROJECT_SOURCE_DIR points to the correct continuable directory.

I'm not completely sure if this is intended, hence I'm creating an issue instead of a pull request.

Commit Hash

9247e7b

Expected Behavior

Running 'cmake ..' from the build directory to successfully configure the CMake project

Actual Behavior

CMake throws errors because it's unable to find:

  • ${CMAKE_SOURCE_DIR/}cmake/compiler/*.cmake
  • ${CMAKE_SOURCE_DIR}/cmake/macros/group_sources.cmake

Steps to Reproduce

  • Create a directory with a valid CMakeLists.txt with add_subdirectory(continuable)
  • git submodule add https://github.com/Naios/continuable.git
  • git submodule update --init --recursive
  • Create a build directory
  • cmake ..
Produces output similar to:
CMake Error at continuable/cmake/configure_compiler.cmake:29 (include):
  include could not find load file:
    ${CMAKE_SOURCE_DIR}/cmake/compiler/gcc.cmake
Call Stack (most recent call first):
  continuable/cmake/CMakeLists.txt:26 (include)
  continuable/CMakeLists.txt:56 (include)
CMake Error at continuable/cmake/configure_macros.cmake:23 (include):
  include could not find load file:
    ${CMAKE_SOURCE_DIR}/cmake/macros/group_sources.cmake
Call Stack (most recent call first):
  continuable/cmake/CMakeLists.txt:27 (include)
  continuable/CMakeLists.txt:56 (include)

Your Environment

  • OS: Linux 4.14.79-1-MANJARO
  • Compiler and version: tested both GCC 8.2.1 and clang 7.0.0, cmake 3.12.4
  • Standard library (if non default): default

Simple example does not execute THEN block on Linux

@Naios I have tried a simple test but the continuation block is not executed (the part inside then()).


Actual Code

auto my_sleep(int millisecs) {
    return cti::make_continuable<std::string>(
	[millisecs](auto&& promise){
	    printf("-- running my_sleep(%d)\n", millisecs);
	    std::this_thread::sleep_for(std::chrono::milliseconds(millisecs));
	    printf("-- end of my_sleep(%d)\n", millisecs);
	    return "time goes on";
	});
}

int main(){
    printf("Start\n");

    my_sleep(2000)
	.then(
	    []( std::string result ){
		printf( "then %s\n", result.data() );
	    });

    printf("End\n");
}

Compiler Options

g++ -std=c++14 -Wall -Og -I. -g -pthread main.cpp

Actual Output

Start
-- running my_sleep(2000)
-- end of my_sleep(2000)
End

My Environment

  • OS: Linux Mint 20
  • Compiler and version: GCC 9.3.0

How to start continuable eagerly

@Naios

TLDR: Is there a way to get eager continuable invocation for async code like in javascript?

A common use pattern of async code is this (javascript):

function backgroundWork(timeMs) {
    return new Promise(resolve => {
        console.log(`Starting background work...`);
        setTimeout(() => {
            console.log(`background work done`);
            resolve();
        }, timeMs)
    });
}

function root() {
    let promises = [];

    promises.push(backgroundWork(1000));
    promises.push(backgroundWork(2000));
    promises.push(backgroundWork(3000));

    console.log(`Now doing some expensive calculations...`);
    const start = new Date().valueOf();
    while (new Date().valueOf() < start + 5000);  // busy wait, ugh...
    console.log(`Calculations done`);

    return Promise.all(promises);
}

// main:
root().then(() => console.log(`all done`));

Output:

$ time node prDemo.js
Starting background work...
Starting background work...
Starting background work...
Now doing some expensive calculations...
Calculations done
background work done
background work done
background work done
all done
5.063 secs

Because the background work (1 s, 2 s, and 3 s) were all started before the foreground calculation (5 s), the whole program ran only 5 s.

Now I'm trying to replicate the same with C++ and continuable, using the same structure as in javascript:

#include <iostream>
#include <chrono>
#include <thread>
#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>

#include <experimental/coroutine>

#define CONTINUABLE_WITH_EXPERIMENTAL_COROUTINE
#include <continuable/continuable.hpp>

namespace asio = boost::asio;

asio::io_service io;

cti::continuable<> backgroundWork(const std::chrono::duration<uint64_t> &t)
{
    using namespace std;
    using boost::system::error_code;
    return cti::make_continuable<void>([&](auto &&pr) {
        std::cout << "Starting background work..."  << std::endl;
        auto timer = std::make_shared<asio::steady_timer>(io, t);
        timer->async_wait([timer, pr=move(pr)](const error_code&) mutable {
            std::cout << "background work done" << std::endl;
            pr.set_value();
        });
    });
}

cti::continuable<> root()
{
    std::vector<cti::continuable<>> promises;

    promises.push_back(backgroundWork(std::chrono::seconds{1}));
    promises.push_back(backgroundWork(std::chrono::seconds{2}));
    promises.push_back(backgroundWork(std::chrono::seconds{3}));

    std::cout << "Now doing some expensive calculations..." << std::endl;

    // the idea is that the backgroundWork tasks should have started
    // their async operation already so that they can complete while we're
    // doing the foreground calculation.

    std::this_thread::sleep_for(std::chrono::seconds{5});
    std::cout << "Calculations done" << std::endl;

    co_await cti::when_all(promises.begin(), promises.end());
}

int main()
{
    root()
        .then([](){std::cout << "all done\n";})
        .fail([](){std::cerr << "fail\n";});

    io.run();
}

Output:

# time ./coro
Now doing some expensive calculations...
Calculations done
Starting background work...
Starting background work...
Starting background work...
background work done
background work done
background work done
all done

real	0m8.010s
user	0m0.002s
sys	0m0.000s

As you can see, the background tasks started only after the foreground work completed. As a result, the whole program required 8 s to run.
This is documented in the tutorial, but is there a way to get eager evaluation like in javascript?

CONTINUABLE_WITH_UNHANDLED_EXCEPTION

@Naios

Hello,
when I apply a continuable_base to_future(),"Illegal instruction" happens! Then I find it's something about CONTINUABLE_WITH_UNHANDLED_EXCEPTION. Now, I'm confused about CONTINUABLE_WITH_UNHANDLED_EXCEPTION. Why this happen? Thanks!


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}

Compile error in VS2015/VS2017

@Naios

If I use Platform toolset VS2017,Compile error:
\continuable-3.0.0\include\continuable\continuable-types.hpp(54): error C2923: "fu2::function_base": For the parameter "Capacity", "Size" is not valid Template type variable
Continuable-3.0.0\include\continuable\continuable-types.hpp(53): error C2974: 'fu2::function_base' : template is invalid for 'Capacity' and should be type

If I change to use Platform toolset VS2015,Compile error:
Continuable-3.0.0\dep\function2\include\function2\function2.hpp(126): error C2665: "std::forward": None of the 2 overloads can convert all parameter types

Expected Behavior

{Please write here}

Actual Behavior

{Please write here}

Steps to Reproduce

New a win32 console project with Continuable header file:
#include "pch.h"
#include
#include <continuable/continuable.hpp>

int main()
{
std::cout << "Hello World!\n";
//auto one = cti::make_ready_continuable(0);
//cti::continuable<int, float, char> three = cti::make_ready_continuable(0, 1.f, '2');
}

Your Environment

  • OS: {Please write here - Windows/Linux dist/OSX}
    Win7 x64

  • Compiler and version: {Please write here - MSVC/Clang/GCC/Other}
    IDE:Visual Studio 2017 (v15.9.13)
    Platform toolset: MSVC2017-x86
    Platform toolset: MSVC2015-x86

  • Standard library (if non default): {Please write here}
    Win32 Console
    continuable-3.0.0
    function2-4.0.0

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}

Failed assertion when giving make_exceptional_continuable() to when_seq()

Hi, @Naios!

It seems I found another issue: when_seq() connection operator can't deal with ready exceptional continuables (i.e. created by make_exceptional_continuable()). It doesn't have the same problem with lazy exceptional continuables. Moreover, when_all() and when_any() operators don't have the problem at all. Neither does the chaining operator (>>).

To me this is a corner case and not a high priority. A workaround is to chain something to ready continuables before giving them to when_seq() (see Steps to Reproduce).


Commit Hash

4.2.0 release

Expected Behavior

when_seq() forwards the exception like it would for a lazy exceptional continuable.

Actual Behavior

Assertion failed: is_value(), file *redacted*\continuable\include\continuable/detail/utility/result-variant.hpp, line 167

Steps to Reproduce

auto eptr = std::make_exception_ptr(std::exception("test"));
// case 1: lazy exceptional continuable is fine
cti::when_seq(cti::async([eptr]() -> int { std::rethrow_exception(eptr); }));
// case 2: ready exceptional continuable triggers an assertion failure
cti::when_seq(cti::make_exceptional_continuable<int>(eptr));
// case 3: chaining something to a ready exceptional continuable fixes the issue
cti::when_seq(cti::make_exceptional_continuable<int>(eptr).then([](auto) {}));

Your Environment

  • OS: Windows
  • Compiler and version: MSVC 2019 v16.11.18
  • defined CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS

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):

How do you run final cleanup with a chain?

@Naios

I am currently using https://github.com/xhawk18/promise-cpp and would like to move to continuable since I am using native asio. One thing that is holding me back is the Promise::finally(FUNC_ON_FINALLY on_finally) method. I use this because I need to have a few cleanup operations that can only run after the entire chain has been resolved. I was having issues finding a way to make this with next(...) without duplicating code in both functions. Am I missing something?

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

how do you convert a variadic function with callback to a continuable?

@Naios

I would like to convert a function with the following signature into a continuable:

typedef void (CallbackFn)(struct CallbackContext *, void *, void *);
int async_call(const char *param, CallbackFn cb, void *privateData, const char *qformat, ...);

The closest example I've found is the promisify::from example in the tutorial but promisify wants the callback to have a different signature. It would also be nice to retain the varargs in the top-level call but perhaps it is difficult. I like the design of your interface and it would fit in nicely to my project but the template error messages can be daunting.

Any help appreciated - hopefully it is of interest to other users of your library,
thanks!

"There is no way to call the given object with these arguments"

@Naios

It looks to me like the documentation is suggesting that this is possible:

   std::vector<cti::continuable<int>> futures;

   cti::when_all(std::move(futures))
      .then([](std::vector<int> &&futureResults) {})
      .apply(cti::transforms::wait());

but i get this:

continuable/detail/utility/util.hpp:157:25: error: static assertion failed: There is no way to call the given object with these arguments!
  157 |         sizeof...(Args) > Keep,

Commit Hash

4.1.0 6bffb44

  • OS: {Please write here - Centos7
  • Compiler and version: gcc 10.2

clang 15 on godbolt gives the same 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!

Question - Convenience with using executors

@Naios
Hello.
I am trying to use custom executors to push the work on to specific thread. I have this working atm. However, I am trying to make it more convenient to use.

I will try to demonstrate what I would like to do with your examples.
In order to push the work to the right queue, I am capturing the identifier of the queue in the executor.

int queueId = 1;
auto executor = [queueId](auto&& work) {
   pushWorkToQueue(queueId, std::forward<decltype(work)>(work));
};
 
http_request("github.com")
   .then([](std::string github) {
     // Do something...
   }, executor);

This is working for me. I am however curious if i could make a factory method to create the executor. Something of the form:

template <class T>
auto makeQueueExecutor(int queueId) {
   return [queueId](T&& work) {      
      pushWorkToQueue(queueId, std::forward<decltype(work)>(work));
   };
}

http_request("github.com")
   .then([](std::string github) {
     // Do something...
   },  makeQueueExecutor(queueId));

This becomes tricky as the template parameter T can't be inferred.

This is a contrived example. In practice the parameters I need to create the executor are more complex, and it would be convenient to have a factory.

Can you think of any way to support this?

Thanks for the help.

VS 16.2: parameter pack must be expanded in this context

@Naios

Visual Studio 16.2 has introduced a bug with parameter pack expansions and this is affecting continuable.

[100%] Building CXX object test/unit-test/CMakeFiles/test-continuable-base.dir/test-continuable.cpp.obj
test-continuable.cpp
D:\Source\Projects\continuable\include\continuable/continuable-result.hpp(137): error C3520: 'Args': parameter pack must be expanded in this context
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.22.27905\include\type_traits(290): note: see reference to function template instantiation '_Add_reference<_Ty,void>::_Rvalue std::declval(void) noexcept' being compiled
D:\Source\Projects\continuable\include\continuable/detail/operations/loop.hpp(166): note: see reference to class template instantiation 'cti::result<>' being compiled
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.22.27905\include\chrono(591): note: see reference to class template instantiation 'std::chrono::duration<double,std::ratio<1,1>>' being compiled
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.22.27905\include\chrono(169): note: see reference to class template instantiation 'std::chrono::duration<__int64,std::nano>' being compiled
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.22.27905\include\chrono(570): note: see reference to class template instantiation 'std::chrono::time_point<std::chrono::steady_clock,std::chrono::steady_clock::duration>' being compiled
D:\Source\Projects\continuable\include\continuable/continuable-result.hpp(136): error C2672: 'std::declval': no matching overloaded function found
D:\Source\Projects\continuable\include\continuable/continuable-result.hpp(137): error C2893: Failed to specialize function template '_Add_reference<_Ty,void>::_Rvalue std::declval(void) noexcept'
D:\Source\Projects\continuable\include\continuable/continuable-result.hpp(137): note: With the following template arguments:
D:\Source\Projects\continuable\include\continuable/continuable-result.hpp(137): note: '_Ty=Args'
D:\Source\Projects\continuable\include\continuable/continuable-result.hpp(150): error C3520: 'Args': parameter pack must be expanded in this context
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.22.27905\include\type_traits(290): note: see reference to function template instantiation '_Add_reference<_Ty,void>::_Rvalue std::declval(void) noexcept' being compiled
D:\Source\Projects\continuable\include\continuable/continuable-result.hpp(149): error C2672: 'std::declval': no matching overloaded function found
D:\Source\Projects\continuable\include\continuable/continuable-result.hpp(150): error C2893: Failed to specialize function template '_Add_reference<_Ty,void>::_Rvalue std::declval(void) noexcept'
D:\Source\Projects\continuable\include\continuable/continuable-result.hpp(150): note: With the following template arguments:
D:\Source\Projects\continuable\include\continuable/continuable-result.hpp(150): note: '_Ty=Args'

Workaround

Removing the second template parameter on line 135 and the third parameter on line 148 seems to work around the issue.

This seems to be a MSVC bug when expanding std::declval<Args>()... expressions.


Your Environment

  • OS: Windows 10
  • Compiler and version: VS 16.2 (Microsoft (R) C/C++ Optimizing Compiler Version 19.22.27905)

Stopping a continuable in a failure handler makes wait() hang forever

First of all, thanks for this great library @Naios! I really appreciate all the work you've put into it!

In some parts of my project I need to resolve a continuation chain synchronously and get its result. The most obvious way of doing that is applying the cti::transforms::wait() transform. While it seems to work most of the time, I discovered two scenarios, in which it would hang the wait forever (see steps to reproduce for code samples):

  1. When a failure handler returns an empty_result (i.e. stop)
  2. When a failure handler returns nothing (void)

The first one requires intent, so it's less dangerous. The second scenario, unfortunately, makes it easy to shoot oneself in the foot by mistake.


Commit Hash

Latest

Expected Behavior

Waiting on a stopped continuable does not hang. Either returning an empty result or throwing an exception would be infinitely better.

Actual Behavior

Waiting on a stopped continuable hangs forever. A workaround is to use timed waits (wait_for or wait_until).

Steps to Reproduce

  1. Failure handler returns an empty_result
auto eptr = std::make_exception_ptr(std::exception("test"));
auto continuable = cti::make_exceptional_continuable<void>(eptr).fail([]() { return cti::stop(); });
std::move(continuable).apply(cti::transforms::wait()); // waits forever
  1. Failure handler returns void
auto eptr = std::make_exception_ptr(std::exception("test"));
auto continuable = cti::make_exceptional_continuable<void>(eptr).fail([]() { /*do nothing*/ });
std::move(continuable).apply(cti::transforms::wait()); // waits forever

Your Environment

  • OS: Windows
  • Compiler and version: MSVC 2019 v16.11.9

boost::beast::ssl_stream::async_handshake() doesn't accept cti::use_continuable

@Naios

boost::beast::ssl_stream<boost::beast::tcp_stream>* stream;
const auto f = stream->async_handshake(boost::asio::ssl::stream_base::client, boost::asio::use_future); // compiles
const auto g = stream->async_handshake(boost::asio::ssl::stream_base::client, cti::use_continuable); // error
---
error: no matching function for call to 'boost::beast::ssl_stream<boost::beast::basic_stream<boost::asio::ip::tcp, boost::asio::any_io_executor, boost::beast::unlimited_rate_policy> >::async_handshake(boost::asio::ssl::stream_base::handshake_type, const cti::use_continuable_t<>&)'
  143 |    const auto g = stream->async_handshake(boost::asio::ssl::stream_base::client, cti::use_continuable);

it works fine with other boost & beast APIs.

Commit Hash

6bffb44 (4.1.0 release)

  • OS: CentOS7
  • Compiler and version: gcc (GCC) 10.2.1 20210130 (Red Hat 10.2.1-11)
  • boost 1.77.0 release

Amalgamation for 4.0.0

@Naios

Congratulations on release 4.0.0, the changes look really useful. Get's a feeling of javascript's Promise and async/await into C++!

Anyway, can you please provide an amalgamation for release 4.0.0 and link it in the documentation?

Return value from fail handler crash the program.

@Naios

When I debug issue #46, I found another bug. It can be reproduced by the following code. I'd like to fix the bug, but have not caught the whole picture yet.


Expected Behavior

Finish normally.

Actual Behavior

Crashed at CTI_DETAIL_TRAP(); in macro CONTINUABLE_HAS_EXCEPTIONS.

image

Steps to Reproduce

make_exceptional_continuable<int>(supply_test_exception())
               .fail([](){ return 1; });

Your Environment

  • OS: macOS Big Sur
  • Compiler and version: Clang 11.0.3
  • Standard library (if non default): {Please write here}

Coroutine support - promise.get_future()?

First off, thank you for the library - the approach is a refreshing improvement over std::future and other options, and making it executor-agnostic was an excellent choice!

This is more of a question than an issue, but might lead to a doc/code patch eventually 😄

In a85040b a basic skeleton for std::experimental::coroutine_traits was added. However, this currently does not appear to be functional - most of the code in there is commented out (and refers to boost::promise instead of cti::continuable::promise).

Is this under active development? The README implies that co_await is already usable:

https://github.com/Naios/continuable#coroutines

but aside from the exception codepath, that does not seem possible with the current 2.0.0 version? There also does not seem to be a way to get to the continuable from a promise instance (which I think would be required for get_return_object to work).

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}

Forward declarations are no longer allowed in type-erased continuables

Hello @Naios

Somewhere after 4d58e3b Ts in cti::continuables<Ts...> can no longer have types with a forward declaration when declaring the continuable as a return type in a function call.

struct forward_decl_type;
cti::continuable<forward_decl_type> fails_with_forward_decls();

This simple statement compiles fine with 4d58e3b but fails in the current master branch.


Commit Hash

Working fine in 4d58e3b, not working in master.

Expected Behavior

A header containing the declaration above should compile fine (as it did in 4d58e3b) without the need to fully define forward_decl_type. The compilation can (and should) still fail when calling fails_with_forward_decls without fully defining forward_decl_type.

Actual Behavior

The declaration of fails_with_forward_decls returning a cti::continuable<forward_decl_type> when forward_decl_type is a forward declaration fails to compile.

Your Environment

  • OS: Windows 10
  • Compiler and version: Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27025.1 for x64

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

Example slideshow returns 134

@Naios


Commit Hash

6bffb44 / 4.1.0

Expected Behavior

Return code is 0.

Actual Behavior

Return error code 134.

Steps to Reproduce

Execute example Slideshow.

Your Environment

  • OS: Linux x86_64
  • Compiler and version: Release, gcc 5
  • Standard library (if non default): libstdc++11

Logs

More information and logs here

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.

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.

Status of the codebase

@Naios

Hi. Your library looks wonderful for our use case.

  1. Do you think a codebase is mature enough to be used in production environment?
  2. What is the status of 4.0.0? There is no release tag for this version.

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.,
boostorg/asio@3f680fe
boostorg/asio@77b14ff

I have implemented an integration on a fork here:
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.

MSVC 2019 build error in cti::detail::transforms::wait_relaxed()

Hi, @Naios!

Found another one ;)
MSVC 2019 seems to have a problem constructing cti::detail::transforms::unsafe_unlocker with initializer list syntax inside cti::detail::transforms::wait_relaxed().

To fix it, there needs be a constructor such as the following:

unsafe_unlocker(std::atomic_bool* ready, condition_variable_t* cv,
                std::mutex* mutex, Result* result)
  : ready_{ready}, cv_{cv}, mutex_{mutex}, result_{result} {}

Commit Hash

4.2.0 release

Expected Behavior

No build errors.

Actual Behavior

*redacted*\continuable\include\continuable\detail\transforms\wait.hpp(130): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'cti::detail::transforms::unsafe_unlocker<Result>'
          with
          [
              Result=cti::result<>
          ]
  *redacted*\continuable\include\continuable/detail/transforms/wait.hpp(135): note: No constructor could take the source type, or constructor overload resolution was ambiguous
  *redacted*\continuable\include\continuable/detail/transforms/wait.hpp(153): note: see reference to function template instantiation 'Result cti::detail::transforms::wait_relaxed<cti::detail::base::ready_continuation<>,cti::detail::identity<>,cti::result<>>(cti::continuable_base<cti::detail::base::ready_continuation<>,cti::detail::identity<>> &&)' being compiled
          with
          [
              Result=cti::result<>
          ]
  *redacted*\continuable\include\continuable/transforms/wait.hpp(78): note: see reference to function template instantiation 'void cti::detail::transforms::wait_and_unpack<cti::detail::base::ready_continuation<>,cti::detail::identity<>>(cti::continuable_base<cti::detail::base::ready_continuation<>,cti::detail::identity<>> &&)' being compiled
  *redacted*\continuable\include\continuable/continuable-base.hpp(480): note: see reference to function template instantiation 'void cti::transforms::wait::<lambda_1>::operator ()<Continuable>(_T1 &&) const' being compiled
          with
          [
              Continuable=cti::continuable_base<cti::detail::base::ready_continuation<>,cti::detail::identity<>>,
              _T1=cti::continuable_base<cti::detail::base::ready_continuation<>,cti::detail::identity<>>
          ]
  ..\..\..\continuable_test.cpp(43): note: see reference to function template instantiation 'void cti::continuable_base<cti::detail::base::ready_continuation<>,cti::detail::identity<>>::apply<cti::transforms::wait::<lambda_1>>(T &&) &&' being compiled
          with
          [
              T=cti::transforms::wait::<lambda_1>
          ]
*redacted*\continuable\include\continuable\detail\transforms\wait.hpp(130): error C2672: 'cti::continuable_base<cti::detail::base::ready_continuation<>,cti::detail::identity<>>::next': no matching overloaded function found

Steps to Reproduce

cti::make_ready_continuable().apply(cti::transforms::wait());

Your Environment

  • OS: Windows
  • Compiler and version: MSVC 2019 v16.11.18

Explicit return types for cti::make_continuable<>()

@Naios

I appreciate that continuable has been written making heavy use of type erasure. That is not my problem per-se. The part I'm struggling with is how to explicitly define the return type as specified by ct::make_continuable. What is the type?

///////////////////////////////////////////////////////////////////////////
// foo.hpp
///////////////////////////////////////////////////////////////////////////

class foo
{
public:

    enum class foo_result
    {
        ok = 0,
        error = 1,
        // ...
        // ...
    };

    foo() = default;
    ~foo() = default;

    cti::continuable<foo_result> initialise_deferred();
    // ^^^^^^^^^^^^^^^^^^^^^^^^^ - What should the return type be?

    cti::continuable<foo_result> finalise_deferred();
    // ^^^^^^^^^^^^^^^^^^^^^^^^^ - What should the return type be?
};


///////////////////////////////////////////////////////////////////////////
// foo.cpp
///////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
cti::continuable<foo_result> foo::initialise_deferred()
{
    return cti::make_continuable<foo_result>([](){ // ... });
}

//////////////////////////////////////////////////////////////////////////
cti::continuable<foo_result> foo::finalise_deferred()
{
    return cti::make_continuable<foo_result>([](){ // ... });
}
  • OS: Linux via Ubuntu 18.04
  • Compiler and version: GCC 7.3
  • Standard library (if non default): Default (glibc)

compile error with clang 14

@Naios

I have been using gcc10 on centos7, and that has been working fine, but i just tried clang on ubuntu, and i'm getting this error:

$ cat test.cpp
#include <coroutine>
#include <continuable/continuable.hpp>

cti::continuable<int> foo()
{
        co_return 3;
}

$ clang++ --version
Ubuntu clang version 14.0.0-1ubuntu1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

$ clang++ -I. -std=c++20 -c test.cpp
test.cpp:4:23: error: this function cannot be a coroutine: 'std::coroutine_traits<cti::continuable_base<cti::detail::erasure::continuation<int>, cti::detail::identity<int>>>' has no member named 'promise_type'
cti::continuable<int> foo()
                      ^
1 error generated.

I tried both libstdc++ & libc++, same error.

I also found it odd that I needed to explicitly include <coroutine>...


master

Your Environment

  • OS: Ubuntu 22.04

Feature Request/Question: zero-allocation support

Thanks for your great library; I am excited to finally see proper promises in C++ :D
Now to my question: Would it be possible to support environments in which allocation is not an option? Under which conditions are allocations mandatory at the moment?

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

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.

redundant move in return statement

@Naios

I get the following when building the current master branch (using cmake). I get the same thing when building my own code using the library, with optimizations enabled:

[0/2] Re-checking globbed directories...
[11/158] Building CXX object test/unit-test/CMakeFiles/test-continuable-single.dir/single/test-continuable-result.cpp.o
In file included from /home/user/continuable/include/continuable/continuable-result.hpp:37,
                 from /home/user/continuable/test/unit-test/single/test-continuable-result.cpp:27:
/home/user/continuable/include/continuable/../continuable/detail/utility/result-trait.hpp: In instantiation of ‘static cti::detail::result_trait<T>::surrogate_t cti::detail::result_trait<T>::wrap(T) [with T = std::shared_ptr<int>; cti::detail::result_trait<T>::surrogate_t = std::shared_ptr<int>]’:
/home/user/continuable/include/continuable/continuable-result.hpp:159:29:   required from ‘cti::result<T>::result(FirstArg&&, Args&& ...) [with FirstArg = std::shared_ptr<int>; Args = {}; T = {std::shared_ptr<int>}]’
/home/user/continuable/test/unit-test/single/test-continuable-result.cpp:256:55:   required from here
/home/user/continuable/include/continuable/../continuable/detail/utility/result-trait.hpp:65:25: warning: redundant move in return statement [-Wredundant-move]
   65 |     return std::move(arg);
      |                         ^
/home/user/continuable/include/continuable/../continuable/detail/utility/result-trait.hpp:65:25: note: remove ‘std::move’ call

Commit Hash 63e3ed4

Steps to Reproduce

mkdir build
cd build
cmake -G Ninja ..
ninja-build

Your Environment

  • OS: centos7
  • Compiler and version: gcc 10.2

when_seq gives error on VS2019

@Naios

VS2019. Simple example for cti::when_seq from cti::continuable github page gives the following error:

Sample code:

cti::when_seq(0, 1, cti::make_ready_continuable(2, 3), 4, 5) .then([](int r0, int r1, int r2, int r3, int r4) { // ... });

inc\continuable\continuable/detail/core/base.hpp(143): error C2327: 'cti::detail::connection::connection_finalizer<cti::detail::connection::connection_strategy_seq_tag>::finalize::<lambda_2c21493e75eda026f33efcadc32930e9>::result': is not a type name, static, or enumerator inc\continuable\continuable/detail/core/base.hpp(168): note: see reference to class template instantiation 'cti::detail::base::proxy_continuable<hint_t,cti::detail::connection::connection_finalizer<cti::detail::connection::connection_strategy_seq_tag>::finalize::<lambda_2c21493e75eda026f33efcadc32930e9>>' being compiled inc\continuable\continuable/detail/connection/connection-seq.hpp(169): note: see reference to function template instantiation 'auto cti::detail::base::attorney::create_from<cti::detail::connection::connection_finalizer<cti::detail::connection::connection_strategy_seq_tag>::finalize::<lambda_2c21493e75eda026f33efcadc32930e9>,cti::detail::identity<int,int,int,int,int,int>>(T &&,Hint,cti::detail::util::ownership)' being compiled with [ T=cti::detail::connection::connection_finalizer<cti::detail::connection::connection_strategy_seq_tag>::finalize::<lambda_2c21493e75eda026f33efcadc32930e9>, Hint=cti::detail::identity<int,int,int,int,int,int> ] inc\continuable\continuable/detail/connection/connection.hpp(191): note: see reference to function template instantiation 'auto cti::detail::connection::connection_finalizer<cti::detail::connection::connection_strategy_seq_tag>::finalize<std::tuple<int,int,cti::continuable_base<cti::detail::base::ready_continuation<int,int>,cti::detail::identity<int,int>>,int,int>>(Connection &&,cti::detail::util::ownership)' being compiled with [ Connection=std::tuple<int,int,cti::continuable_base<cti::detail::base::ready_continuation<int,int>,cti::detail::identity<int,int>>,int,int> ] inc\continuable\continuable/continuable-connections.hpp(150): note: see reference to function template instantiation 'auto cti::detail::connection::apply_connection<cti::detail::connection::connection_strategy_seq_tag,_Ty,_Ty,cti::continuable_base<cti::detail::base::ready_continuation<int,int>,cti::detail::identity<int,int>>,_Ty,_Ty>(Strategy,_Ty &&,_Ty &&,cti::continuable_base<cti::detail::base::ready_continuation<int,int>,cti::detail::identity<int,int>> &&,_Ty &&,_Ty &&)' being compiled with [ _Ty=int, Strategy=cti::detail::connection::connection_strategy_seq_tag ] Model\Action\A_Composite.cpp(26): note: see reference to function template instantiation 'auto cti::when_seq<int,int,continuation_t,int,int>(int &&,int &&,continuation_t &&,int &&,int &&)' being compiled

Your Environment

  • OS: Windows 10
  • Compiler and version: MSVC (VS2019)
  • Standard library (if non default): {Please write here}

Add conan recipe

@Naios


Is it possible to add conan (https://conan.io/ C++ open source package manager) recipe and publish on bintray? It will be really helpful for other depelopers. For example: third party developer can add

[requires] continuable/3.0.0@naios/stable

to own project without any source compilation. If you @Naios want I'll try to prepare basic recipe for win/linux/mac and will prepare pull request.

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));

Continue-on-fail support - allowing chains to continue with a value even after a fail?

@Naios
Hello. Nice work with this library. it's been fun integrating it into our traditional callback flows.

I am wondering if there's any support to continue-on-fail? Something similar to recover in Scala futures? Basically handling an exception and allowing the chain to continue with a value or re-throwing the exception for the next fail handler to be triggered? I have use-cases where this is very handy.

https://www.scala-lang.org/api/2.12.3/scala/concurrent/Future.html#recover

thanks.

Homogeneous container remapping code fails for some containers

Hi, @Naios !

Thanks for making continuable, it's a neat library!

I passed an absl::InlinedVector<T, N, A> to cti::when_all(), and to my surprise the continuables in it did not get connected to the hierarchy. Investigating further revealed that because of a substitution failure deep inside the container-remapping code, the code degraded from using the container logic to using the plain-value logic (for values "that aren't accepted by the mapper"). Specifically, it failed substitution for rebind_container(). If I understand correctly, it failed because the template type signature of absl::InlinedVector did not match the ones that rebind_container() tries to accept. I'm wondering whether it should somehow match against traits rather than template type parameter shape?


Commit Hash

Used continuable/4.2.0 and abseil/20210324.2 from conan, but I doubt it matters much.

Expected Behavior

Print "Connection timed out\n"

Actual Behavior

Print "hi\n" + trap on exceptional unhandled continuable (SIGILL).

If the code is changed to use std::vector instead, expected behavior is observed.

Steps to Reproduce

Example code:

#include <cstdio>
#include <absl/container/inlined_vector.h>
#include <continuable/continuable.hpp>

int main() {
  absl::InlinedVector<cti::continuable<>, 1> v;
  v.emplace_back(cti::make_exceptional_continuable<void>(std::errc::timed_out));

  cti::when_all(std::move(v))
    .then([]() { std::puts("hi"); })
    .fail([](std::error_condition e) { std::puts(e.message().c_str()); });
  return 0;
}

Your Environment

  • OS: Debian 10
  • Compiler and version: Clang 12
  • Standard library (if non default): (libstdc++-8.3, the default)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.