# Task Bypass Support for `task_group`

Note

To enable this extension, define the `TBB_PREVIEW_TASK_GROUP_EXTENSIONS` macro with a value of `1`.

## Description

The oneAPI Threading Building Blocks (oneTBB) implementation extends the requirements for user-provided function object from tbb::task_group specification to allow them to return a `task_handle` object.

Task Bypassing allows developers to reduce task scheduling overhead by providing a hint about which task should be executed next.

Execution of the deferred task owned by a returned `task_handle` is not guaranteed to occur immediately, nor to be performed by the same thread.

    tbb::task_handle task_body() {
        tbb::task_handle next_task = group.defer(next_task_body);
        return next_task;
    }

## API

### Header

    #define TBB_PREVIEW_TASK_GROUP_EXTENSIONS 1
    #include <oneapi/tbb/task_group.h>

### Synopsis

    namespace oneapi {
        namespace tbb {
            class task_group {
            public:
                // Only the requirements for the return type of function F are changed
                template <typename F>
                task_handle defer(F&& f);

                // Only the requirements for the return type of function F are changed
                template <typename F>
                task_group_status run_and_wait(const F& f);

                // Only the requirements for the return type of function F are changed
                template <typename F>
                void run(F&& f);
            }; // class task_group
        } // namespace tbb
    } // namespace oneapi

### Member Functions

    template <typename F>
    task_handle defer(F&& f);

    template <typename F>
    task_group_status run_and_wait(const F& f);

    template <typename F>
    void run(F&& f);

The `F` type must meet the Function Objects requirements described in the [function.objects] section of the ISO C++ Standard.

Extension

`F` may return a `task_handle` object. If the returned handle is non-empty and owns a task without dependencies, it serves as an optimization hint for a task that could be executed next.

The returned `task_handle` must not be explicitly submitted with `task_group::run` or another submission function, otherwise, the behavior is undefined.

If the returned handle was created by a `task_group` other than `*this`, the behavior is undefined.

### Example

The example below demonstrates how to process a sequence in parallel using `task_group` and the divide-and-conquer pattern.

    #define TBB_PREVIEW_TASK_GROUP_EXTENSIONS 1
    #include "oneapi/tbb/task_group.h"

    template <typename Iterator, typename Function>
    struct for_task {
        tbb::task_handle operator()() const {
            tbb::task_handle next_task;

            auto size = end - begin;
            if (size < serial_threshold) {
                // Execute the work serially
                for (Iterator it = begin; it != end; ++it) {
                    f(*it);
                }
            } else {
                // Enough work to split the range
                Iterator middle = begin + size / 2;

                // Submit the right subtask for execution
                tg.run(for_task<Iterator, Function>{middle, end, f, tg});

                // Bypass the left subtask
                next_task = tg.defer(for_task<Iterator, Function>{begin, middle, f, tg});
            }
            return next_task;
        }

        Iterator begin;
        Iterator end;
        Function f;
        tbb::task_group& tg;
    }; // struct for_task

    template <typename RandomAccessIterator, typename Function>
    void par_for_each(RandomAccessIterator begin, RandomAccessIterator end, Function f) {
        tbb::task_group tg;
        // Run the root task
        tg.run_and_wait(for_task<RandomAccessIterator, Function>{begin, end, std::move(f), tg});
    }