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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions