Quick Start

Requirements

Assumed Knowledge

  • C++20 coroutines, concepts, and ranges

  • Basic concurrent programming

Compiler Support

  • GCC 12+

  • Clang 17+

  • Apple-Clang (macOS 14+)

  • MSVC 14.34+

  • MinGW

Dependencies

None. Capy is self-contained and does not require Boost.

Minimal Example

Create a file hello_coro.cpp:

#include <boost/capy/task.hpp>
#include <boost/capy/ex/run_async.hpp>
#include <boost/capy/ex/thread_pool.hpp>
#include <iostream>

namespace capy = boost::capy;

// A coroutine that returns a value
capy::task<int> answer()
{
    co_return 42;
}

// A coroutine that awaits another coroutine
capy::task<void> greet()
{
    int n = co_await answer();
    std::cout << "The answer is " << n << "\n";
}

int main()
{
    capy::thread_pool pool(1);

    // Start the coroutine on the pool's executor
    capy::run_async(pool.get_executor())(greet());

    // join() waits for outstanding work to complete; the pool
    // destructor only stops the pool and discards pending work
    pool.join();
}

Build and Run

Capy is not installed as a system package, so build it first:

cmake -B build && cmake --build build

Replace both paths below with where you built Capy:

g++ -std=c++20 -I/path/to/capy/include -o hello_coro hello_coro.cpp \
    /path/to/capy/build/libboost_capy.a -pthread
If your prorgam is build with CMake, link it against Boost::capy.

Then run the compiled program:

./hello_coro

Expected output:

The answer is 42

What Just Happened?

  1. answer() creates a suspended coroutine that returns 42

  2. greet() creates a suspended coroutine that awaits answer()

  3. run_async(executor)(greet()) starts greet() on the pool’s executor

  4. greet() runs until it hits co_await answer()

  5. answer() runs and returns 42

  6. greet() resumes with the result and prints it

  7. greet() completes, pool.join() returns, and main() exits

Both coroutines ran on the same executor because affinity propagated automatically through the co_await.

Handling Results

To receive a task’s result outside a coroutine, provide a completion handler:

capy::run_async(executor, [](int result) {
    std::cout << "Got: " << result << "\n";
})(answer());

Handling Errors

Exceptions propagate through coroutine chains. To handle them at the top level:

capy::run_async(executor,
    [](int result) {
        std::cout << "Success: " << result << "\n";
    },
    [](std::exception_ptr ep) {
        try {
            if (ep) std::rethrow_exception(ep);
        } catch (std::exception const& e) {
            std::cerr << "Error: " << e.what() << "\n";
        }
    }
)(might_fail());

Next Steps