Notice: file_put_contents(): Write of 1459 bytes failed with errno=28 No space left on device in /var/www/group-telegram/post.php on line 50

Warning: file_put_contents(): Only 20480 of 21939 bytes written, possibly out of free disk space in /var/www/group-telegram/post.php on line 50
C++95 | Telegram Webview: cxx95/75 -
Telegram Group & Telegram Channel
#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.group-telegram.com/fr/cxx95.com/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
👍10🖕1



group-telegram.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.group-telegram.com/fr/cxx95.com/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:
group-telegram.com/cxx95/75

View MORE
Open in Telegram


Telegram | DID YOU KNOW?

Date: |

As a result, the pandemic saw many newcomers to Telegram, including prominent anti-vaccine activists who used the app's hands-off approach to share false information on shots, a study from the Institute for Strategic Dialogue shows. Recently, Durav wrote on his Telegram channel that users' right to privacy, in light of the war in Ukraine, is "sacred, now more than ever." WhatsApp, a rival messaging platform, introduced some measures to counter disinformation when Covid-19 was first sweeping the world. As the war in Ukraine rages, the messaging app Telegram has emerged as the go-to place for unfiltered live war updates for both Ukrainian refugees and increasingly isolated Russians alike. False news often spreads via public groups, or chats, with potentially fatal effects.
from fr


Telegram C++95
FROM American