Skip to content

Race() won't compile if as_tuple() or as_result() used to wrap awaitable parameter(s) #271

Description

@Hyper-AU

Tested against develop and 1.90.0 tag, on Linux using gcc 14.2.0, -std=c++23.

It doesn't appear to be possible to use as_tuple() or as_result() to wrap awaiter parameters to race().

I want to use this approach as it makes it easier to determine the source of an error, rather than relying on catching system_error from race().

I am unsure if this is by design, and couldn't immediately see a workaround other than not using these conversion wrappers.

Reproducer:


#include <boost/cobalt.hpp>
#include <boost/cobalt/io.hpp>
#include <iostream>

using namespace boost;
using namespace std::chrono_literals;

// Uncomment one or none
// #define USE_AS_TUPLE
// #define USE_AS_RESULT

cobalt::main co_main(int, char *[]) {

    std::cout << "Starting co_main\nEnter a character: " << std::flush;

    cobalt::io::stream_file  stdin_stream(::dup(STDIN_FILENO));
    cobalt::io::steady_timer timer(10s);
    char                     buffer[1];

    // Note: stream_file::read_some() used here rather than cobalt::read() because
    // read() doesn't cancel when race is won by timer (see Cobalt Github Issue 270)

#if defined(USE_AS_TUPLE)
    // Won't compile:
    auto result =
        co_await cobalt::race(as_tuple(stdin_stream.read_some(asio::buffer(buffer, 1))), as_tuple(timer.wait()));

    switch (result.index()) {
        case 0: {
            auto [ec, n] = get<0>(result);
            if (ec) {
                std::cout << "Read error: " << ec.what() << std::endl;
            } else {
                std::cout << "Read: " << n << " byte: " << std::string_view(buffer, n) << std::endl;
            }
            break;
        }
        case 1: {
            auto [ec] = get<1>(result);
            if (ec) {
                std::cout << "Timer error: " << ec.what() << std::endl;
            } else {
                std::cout << "Read timed out\n";
            }
            break;
        }
    }
#elif defined(USE_AS_RESULT)
    // Wont compile:
    auto result =
        co_await cobalt::race(as_result(stdin_stream.read_some(asio::buffer(buffer, 1))), as_result(timer.wait()));

    switch (result.index()) {
        case 0: {
            auto r = get<0>(result);
            if (r.error()) {
                std::cout << "Read error: " << r.error().what() << std::endl;
            } else {
                std::cout << "Read: " << *r << " byte: " << std::string_view(buffer, *r) << std::endl;
            }
            break;
        }
        case 1: {
            auto r = get<1>(result);
            if (r.error()) {
                std::cout << "Timer error: " << r.error().what() << std::endl;
            } else {
                std::cout << "Read timed out\n";
            }
            break;
        }
    }

#else
    // Will compile
    try {
        auto result = co_await cobalt::race(stdin_stream.read_some(asio::buffer(buffer, 1)), timer.wait());

        switch (result.index()) {
            case 0: {
                auto r = get<0>(result);
                std::cout << "Read: " << r << " byte: " << std::string_view(buffer, r) << std::endl;
                break;
            }
            case 1: {
                std::cout << "Read timed out\n";
                break;
            }
        }
    } catch (system::system_error & ex) {
        std::cout << "Exception: " << ex.what() << std::endl;
    }
#endif

    std::cout << "Done\n";

    co_return 0;
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions