Контейнер std::variant вызываемых объектов со связанными параметрами без использования динамической памятиC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Контейнер std::variant вызываемых объектов со связанными параметрами без использования динамической памяти

Сообщение Anonymous »

Я хочу сохранить несколько разных вызываемых объектов (разных типов) в контейнере (например, std::array), чтобы вызывать их позже.
Каждый вызываемый объект имеет одинаковый тип возвращаемого значения и одинаковое количество и тип параметров: например, скажем, все эти объекты можно вызывать как int func(void *). Однако они содержат различное количество (возможно, много) параметров (только фундаментального типа), привязанных к различным функциям для каждого вызываемого типа.
Вопрос в том, какой рекомендуемый C++ (C+) +23) способ реализации этого, избегая при этом динамического выделения памяти из-за необходимости хранения параметров связанной функции в вызываемом объекте?
Пример реализации с помощью std::function:

Код: Выделить всё

#include 
#include 
#include 

int foo(int, void *);
int bar(char, double, void *);

int i; char c; double d;

auto callable_foo = std::function{[=](void *p){ return foo(i, p); } // binds i
auto callable_bar = std::function{[=](void *p){ return foo(c, d, p); } // binds c and d

using variant_t = std::variant;

std::array container{callable_foo, callable_bar};
Я знаю, что в этом случае std::variant даже не требуется, поскольку массив адекватных std::function подойдет. Тем не менее (насколько мне известно), std::function имеют ограниченное хранилище для связанных параметров функции и в какой-то момент могут потребовать динамического выделения памяти. То же самое относится и к лямбда-выражениям (если я не ошибаюсь), когда вы храните их в контейнере (или std::function), даже если захват осуществляется только по значению фундаментальных типов.
После долгих поисков и экспериментов я нашел два многообещающих решения:
  • использование std::variant для std:: привязки (например, auto callable_foo = std::bind(foo, i, _1); вместо этого)
  • использование решения в стиле C с пользовательским типом данных для каждого вызываемого объекта, содержащим указатель на функцию и связанные параметры
Подводя итог моим вопросам:
  • есть ли другие решения, кроме (1) и (2) избежать динамического выделения памяти?
  • тип возвращаемого значения std::bind, похоже, не подлежит назначению (скопируйте и переместите, по крайней мере, в моем случае). Как поместить объекты, возвращаемые std::bind, в std::array, где каждый WrapperType имеет элемент данных типа decltype(std::bind(...))?
Решение (2) явно будет работать, но это не так похоже на C++ способ сделать это, и я надеюсь, что язык позволяет сделать это более чистым способом.
Моим любимым решением «я бы хотел» было использование шаблонной специализации std::function, позволяющей чтобы установить размер хранилища единого входа таким образом, чтобы все связанные параметры (размер, определенный во время компиляции) помещались в объект std::function.
Я искал в Google, спросил ChatGPT , прочитал несколько страниц cppreference, поэкспериментировал с реальным кодом, и спросил коллег.

Подробнее здесь: https://stackoverflow.com/questions/792 ... o-using-dy
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»