Skip to content

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

@Hyper-AU

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions