CXX95 Telegram 75
#story

Самое простое объяснение std::function за 15 минут 😦

Этот пост был написан под влиянием крутого видео от Jason Turner "A Simplified std::function Implementation"

Часто люди не задумываются, как работает std::function. Чаще всего знают, что эта штука - обертка над чем-то, что можно "вызвать" как функцию. Кто-то смутно помнит, что std::function вроде как лезет в динамическую память. cppreference не сильно раскрывает внутренности реализации.

Можно сказать, что в C++ есть два типа объектов, на которых работает семантика вызова как функции. Можно условно назвать их Callable. Это:
1️⃣ Сами функции:
    int foo(int a, int b) { return a + b; }
2️⃣ Объекты типов с определенным operator(), часто их называют "функторы":
    struct foo {
int operator()(int a, int b) { return a + b; }
}
Все остальные Callable являются производными от этих двух типов. В том числе лямбды - компилятор их переделывает в структуры с operator(). Про лямбды есть хорошая книга - https://www.tgoop.com/cxx95/48.

А std::function<Signature> должен уметь хранить все возможные Callable с данной сигнатурой.

template<typename Ret, typename... Param>
class function<Ret(Param...)> {
// код реализации
};

Возникает проблема - у std::function должен быть фиксированный размер, но Callable типа 2️⃣ может иметь неопределенный размер. Например, размер структуры у лямбды зависит от того, какие captures он делает.

Поэтому, к сожалению, std::function хранит Callable в куче.
Также нужно использовать виртуальный класс, который для каждого отдельного типа как бы вычислит адрес вызываемого метода:

Виртуальный класс и указатель на кучу:
    struct callable_interface {
virtual Ret call(Param...) = 0;
virtual ~callable_interface() = default;
};
std::unique_ptr<callable_interface> callable_ptr;

Реализация для каждого отдельного типа Callable держит в себе сам объект Callable и метод для вызова operator() по правильному адресу:
    template<typename Callable>
struct callable_impl : callable_interface {
callable_impl(Callable callable_) : callable{std::move(callable_)} {}
Ret call(Param... param) override { return std::invoke(callable, param...); };
Callable callable;
}

Конструктор std::function принимает Callable и создает объект в куче:
    template<typename Callable>
function(Callable callable)
: callable_ptr{std::make_unique<callable_impl<Callable>>(std::move(callable))}
{}

И наконец вызов operator() у самого std::function перенаправляет вызов в содержимый Callable:
    Ret operator()(Param... param) { return callable_ptr->call(param...); }

Вот так выглядит один из способов type erasure в C++ 👍
Please open Telegram to view this post
VIEW IN TELEGRAM



tgoop.com/cxx95/75
Create:
Last Update:

#story

Самое простое объяснение std::function за 15 минут 😦

Этот пост был написан под влиянием крутого видео от Jason Turner "A Simplified std::function Implementation"

Часто люди не задумываются, как работает std::function. Чаще всего знают, что эта штука - обертка над чем-то, что можно "вызвать" как функцию. Кто-то смутно помнит, что std::function вроде как лезет в динамическую память. cppreference не сильно раскрывает внутренности реализации.

Можно сказать, что в C++ есть два типа объектов, на которых работает семантика вызова как функции. Можно условно назвать их Callable. Это:
1️⃣ Сами функции:

    int foo(int a, int b) { return a + b; }
2️⃣ Объекты типов с определенным operator(), часто их называют "функторы":
    struct foo {
int operator()(int a, int b) { return a + b; }
}
Все остальные Callable являются производными от этих двух типов. В том числе лямбды - компилятор их переделывает в структуры с operator(). Про лямбды есть хорошая книга - https://www.tgoop.com/cxx95/48.

А std::function<Signature> должен уметь хранить все возможные Callable с данной сигнатурой.

template<typename Ret, typename... Param>
class function<Ret(Param...)> {
// код реализации
};

Возникает проблема - у std::function должен быть фиксированный размер, но Callable типа 2️⃣ может иметь неопределенный размер. Например, размер структуры у лямбды зависит от того, какие captures он делает.

Поэтому, к сожалению, std::function хранит Callable в куче.
Также нужно использовать виртуальный класс, который для каждого отдельного типа как бы вычислит адрес вызываемого метода:

Виртуальный класс и указатель на кучу:
    struct callable_interface {
virtual Ret call(Param...) = 0;
virtual ~callable_interface() = default;
};
std::unique_ptr<callable_interface> callable_ptr;

Реализация для каждого отдельного типа Callable держит в себе сам объект Callable и метод для вызова operator() по правильному адресу:
    template<typename Callable>
struct callable_impl : callable_interface {
callable_impl(Callable callable_) : callable{std::move(callable_)} {}
Ret call(Param... param) override { return std::invoke(callable, param...); };
Callable callable;
}

Конструктор std::function принимает Callable и создает объект в куче:
    template<typename Callable>
function(Callable callable)
: callable_ptr{std::make_unique<callable_impl<Callable>>(std::move(callable))}
{}

И наконец вызов operator() у самого std::function перенаправляет вызов в содержимый Callable:
    Ret operator()(Param... param) { return callable_ptr->call(param...); }

Вот так выглядит один из способов type erasure в C++ 👍

BY C++95




Share with your friend now:
tgoop.com/cxx95/75

View MORE
Open in Telegram


Telegram News

Date: |

Co-founder of NFT renting protocol Rentable World emiliano.eth shared the group Tuesday morning on Twitter, calling out the "degenerate" community, or crypto obsessives that engage in high-risk trading. On June 7, Perekopsky met with Brazilian President Jair Bolsonaro, an avid user of the platform. According to the firm's VP, the main subject of the meeting was "freedom of expression." To edit your name or bio, click the Menu icon and select “Manage Channel.” How to Create a Private or Public Channel on Telegram? Telegram is a leading cloud-based instant messages platform. It became popular in recent years for its privacy, speed, voice and video quality, and other unmatched features over its main competitor Whatsapp.
from us


Telegram C++95
FROM American