Build With Abdallah logo Build With Abdallah Software · AI · Automation
Tutorial 3 min read Jun 07, 2026

Implementing Coroutine Support in C++26 with Visual Studio 2026

C++26 introduces enhanced coroutine support, which can simplify asynchronous programming and improve performance by reducing the overhead of traditional threading. Coroutines allow

A
Abdallah Mohamed
Senior Full-Stack Engineer
Implementing Coroutine Support in C++26 with Visual Studio 2026

Implementing Coroutine Support in C++26 with Visual Studio 2026

C++26 introduces enhanced coroutine support, which can simplify asynchronous programming and improve performance by reducing the overhead of traditional threading. Coroutines allow functions to pause execution and resume later, making them ideal for tasks like I/O operations, event handling, and more. This tutorial will guide you through setting up a C++26 project in Visual Studio 2026 to leverage coroutine capabilities effectively.

Prerequisites

To follow along with this tutorial, ensure you have the following installed on your system:

  1. Visual Studio 2026: You need the latest version of Visual Studio that supports C++26 features. Download and install it from the Visual Studio website.

  2. C++ Desktop Development Workload: Ensure that during the installation of Visual Studio, you select the "Desktop development with C++" workload.

  3. CMake: Required for building C++ projects. You can install it using the following command:

    # On Windows with Chocolatey
    choco install cmake
    
    # On Linux
    sudo apt-get install cmake
    
    # On macOS with Homebrew
    brew install cmake
    
  4. Git: For version control and to clone any repositories. Install it using:

    # On Windows with Chocolatey
    choco install git
    
    # On Linux
    sudo apt-get install git
    
    # On macOS with Homebrew
    brew install git
    

Project Structure

To keep our project organized, we'll use the following directory structure:

CppCoroutines/
├── build/
├── src/
│   ├── main.cpp
│   └── CMakeLists.txt
└── README.md

Step 1: Setting Up the Project

First, create the project directory and necessary files:

  1. Open a terminal or command prompt.

  2. Create the project root directory and navigate into it:

    mkdir CppCoroutines
    cd CppCoroutines
    
  3. Create the src directory for source files and a build directory for output files:

    mkdir src build
    
  4. Create a basic CMakeLists.txt file in the src directory:

    touch src/CMakeLists.txt
    
  5. Create a main.cpp file in the src directory:

    touch src/main.cpp
    

Step 2: Configuring CMake

Edit the CMakeLists.txt file to set up the project:

# src/CMakeLists.txt

cmake_minimum_required(VERSION 3.26)
project(CppCoroutines)

set(CMAKE_CXX_STANDARD 26)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(CppCoroutines main.cpp)

This CMake configuration specifies that the project requires at least CMake version 3.26 and sets the C++ standard to C++26. It also defines an executable target named CppCoroutines using the main.cpp source file.

Step 3: Writing a Simple Coroutine

Now, let's implement a simple coroutine in main.cpp:

// src/main.cpp

#include <iostream>
#include <coroutine>

struct SimpleCoroutine {
    struct promise_type {
        SimpleCoroutine get_return_object() {
            return SimpleCoroutine{std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
    };

    std::coroutine_handle<promise_type> handle;

    SimpleCoroutine(std::coroutine_handle<promise_type> h) : handle(h) {}
    ~SimpleCoroutine() { handle.destroy(); }
};

SimpleCoroutine simple_coroutine() {
    std::cout << "Hello from coroutine!" << std::endl;
    co_return;
}

int main() {
    auto coroutine = simple_coroutine();
    coroutine.handle.resume();
    return 0;
}

Explanation

  • Coroutine Structure: The SimpleCoroutine struct contains a promise_type which defines how the coroutine behaves. It includes methods for handling initial and final suspension, returning values, and handling exceptions.
  • Coroutine Function: simple_coroutine is a function that uses the co_return keyword to indicate a coroutine. It simply prints a message when executed.
  • Main Function: In main, we create and resume the coroutine. This triggers the execution of the coroutine body, printing "Hello from coroutine!" to the console.

In the next steps, we will build and run this project to see coroutines in action.

Step 4: Building and Running the Project

With our coroutine setup complete, it's time to build and run the project to see it in action.

  1. Navigate to the Build Directory: Open a terminal and ensure you are in the project root directory (CppCoroutines), then move into the build directory:

    cd build
    
  2. Configure the Project with CMake: Run CMake to configure the project. This will generate the necessary build files:

    cmake ../src
    
  3. Build the Project: Use the generated build files to compile the project:

    cmake --build .
    
  4. Run the Executable: After a successful build, execute the program:

    ./CppCoroutines
    

    You should see the following output:

    Hello from coroutine!
    

Step 5: Enhancing the Coroutine

Let's extend our coroutine to perform a simple asynchronous task using std::suspend_always to simulate an asynchronous operation.

Edit main.cpp:

// src/main.cpp

#include <iostream>
#include <coroutine>

struct SimpleCoroutine {
    struct promise_type {
        SimpleCoroutine get_return_object() {
            return SimpleCoroutine{std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_always initial_suspend() { return {}; }
        std::suspend_always final_suspend() noexcept { return {}; }
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
    };

    std::coroutine_handle<promise_type> handle;

    SimpleCoroutine(std::coroutine_handle<promise_type> h) : handle(h) {}
    ~SimpleCoroutine() { handle.destroy(); }
};

SimpleCoroutine simple_coroutine() {
    std::cout << "Starting coroutine..." << std::endl;
    co_await std::suspend_always{};
    std::cout << "Resuming coroutine..." << std::endl;
    co_return;
}

int main() {
    auto coroutine = simple_coroutine();
    std::cout << "Before resuming coroutine." << std::endl;
    coroutine.handle.resume();
    std::cout << "After resuming coroutine." << std::endl;
    coroutine.handle.resume();
    return 0;
}

Explanation

  • Suspension Points: The coroutine now uses std::suspend_always for both initial and final suspension points, allowing it to pause execution and be resumed.
  • Coroutine Execution: The simple_coroutine function prints messages before and after suspension, demonstrating the pause and resume flow.

Complete Working Example

Here's the complete set of files for the project:

CMakeLists.txt

# src/CMakeLists.txt

cmake_minimum_required(VERSION 3.26)
project(CppCoroutines)

set(CMAKE_CXX_STANDARD 26)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(CppCoroutines main.cpp)

main.cpp

// src/main.cpp

#include <iostream>
#include <coroutine>

struct SimpleCoroutine {
    struct promise_type {
        SimpleCoroutine get_return_object() {
            return SimpleCoroutine{std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        std::suspend_always initial_suspend() { return {}; }
        std::suspend_always final_suspend() noexcept { return {}; }
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
    };

    std::coroutine_handle<promise_type> handle;

    SimpleCoroutine(std::coroutine_handle<promise_type> h) : handle(h) {}
    ~SimpleCoroutine() { handle.destroy(); }
};

SimpleCoroutine simple_coroutine() {
    std::cout << "Starting coroutine..." << std::endl;
    co_await std::suspend_always{};
    std::cout << "Resuming coroutine..." << std::endl;
    co_return;
}

int main() {
    auto coroutine = simple_coroutine();
    std::cout << "Before resuming coroutine." << std::endl;
    coroutine.handle.resume();
    std::cout << "After resuming coroutine." << std::endl;
    coroutine.handle.resume();
    return 0;
}

Common Errors and Fixes

  1. CMake Version Error: If you encounter an error about the CMake version, ensure you have at least version 3.26 installed. Upgrade if necessary.

    # Upgrade CMake
    choco upgrade cmake   # Windows
    brew upgrade cmake    # macOS
    sudo apt-get upgrade cmake  # Linux
    
  2. Coroutine Header Not Found: If the <coroutine> header is missing, verify that your compiler supports C++26. Update your compiler if needed.

  3. Unhandled Exception: Ensure that your coroutine properly handles exceptions. Use unhandled_exception() in the promise_type to handle unexpected errors.

Conclusion

This tutorial covered setting up a C++26 project with coroutine support in Visual Studio 2026. We implemented a simple coroutine, demonstrated its pause and resume capabilities, and addressed common errors. Coroutines are a powerful feature for managing asynchronous tasks in C++26, providing a more efficient and readable approach than traditional threading.

Sources