Информация об изменениях

Сообщение Re: move-"cериализация" шаблонных параметров от 12.03.2023 13:41

Изменено 12.03.2023 13:58 rg45

Re: move-"cериализация" шаблонных параметров
Здравствуйте, tapatoon, Вы писали:

T>

T>Есть библиотека (service). Клиенты реализуют колбэк-интерфейс передачи данных (handler). Параметры для передачи передаются библиотеке, которая дёргает колбэк-интерфейс.

T>Хочется такой интерфейс сервиса библиотеки:

T>
T>service::send(T&&... args);
T>


T>И такой интерфейс колбэка (реализуется клиентом)

T>
T>handler::on_send(T&&... args);
T>


T>Ничего, кроме конверта в void* не придумал


T>Будут ещё мнения как это сделать?

T>Спасибо

Лет восемь назад я разработал одну чудо-утилитку, которая, если не в точности, то концептуально очень близка к тому, что тебе нужно. В основе утилиты лежит очень необычный механизм связывания формальных и фактических параметров произвольных вызываемых сущностей. Привычная схема: каждая вызываемая сущность задает какой-то список формальных параметров (фиксированный или переменный), а мы имеем позможность передавать ей различные фактические параметры. В том механизме, о котором рассказываю я, все наоброт: задан произвольный неупорядоченный набор ФАКТИЧЕСКИХ параметров (я назыаю это контекстом). И на одном и том же множестве фактических параметров можно вызывать различные вызываемые сущности, отличающиеся количеством и типом формальных параметров. Для каждой вызываемой сущности утилита выбирает из контекста набор максимально подходящих фактических параметров и выполняет вызов. Связывание формальных и фактических параметров происходит в компайл-тайме и в случае, когда фактический параметр подобрать не удается, возникает ошибка компиляции. Более простые функционалы можно объединять в более сложные. Концептуально примерно так:

auto f = combine(
   [](int i) { std::cout << i << " "; },
   [](const std::string& s) { std::cout << s << " "; },
   [](int i, const std::string& s) { std::cout << i, " " << s; },
   [](const std::string& s, double d) { std::cout << s << " " << d; }
);

f("Hello", 3.14, 42); // -> 42 Hello 42 Hello Hello 3.14

f(3.14, 42); // -> error: could not find actual parameter convertible to const std::string&


На базе такого механизма очень быстро и легко разрабатываются специфические DSL, которые делают разработку в любой прикладной области декларативной и очень наглядной, Получается как бы язык в языке. Правда, пока это используется только для разработки юнит тестов, но в принцие, область применения ни чем не ограничена. Код утилиты не выкладываю, во-первых, потому, что это более 300 строк кода, а во-вторых потому, что она давно уже перестала быть моей собственностью.
Re: move-"cериализация" шаблонных параметров
Здравствуйте, tapatoon, Вы писали:

T>

T>Есть библиотека (service). Клиенты реализуют колбэк-интерфейс передачи данных (handler). Параметры для передачи передаются библиотеке, которая дёргает колбэк-интерфейс.

T>Хочется такой интерфейс сервиса библиотеки:

T>
T>service::send(T&&... args);
T>


T>И такой интерфейс колбэка (реализуется клиентом)

T>
T>handler::on_send(T&&... args);
T>


T>Ничего, кроме конверта в void* не придумал


T>Будут ещё мнения как это сделать?

T>Спасибо

Лет восемь назад я разработал одну чудо-утилитку, которая, если не в точности, то концептуально очень близка к тому, что тебе нужно. В основе утилиты лежит очень необычный механизм связывания формальных и фактических параметров произвольных вызываемых сущностей. Привычная схема: каждая вызываемая сущность задает какой-то список формальных параметров (фиксированный или переменный), а мы имеем позможность передавать ей различные фактические параметры. В том механизме, о котором рассказываю я, все наоброт: задан произвольный неупорядоченный набор ФАКТИЧЕСКИХ параметров (я назыаю это контекстом). И на одном и том же множестве фактических параметров можно вызывать различные вызываемые сущности, отличающиеся количеством и типом формальных параметров. Для каждой вызываемой сущности утилита выбирает из контекста набор максимально подходящих фактических параметров и выполняет вызов. Связывание формальных и фактических параметров происходит в компайл-тайме и в случае, когда фактический параметр подобрать не удается, возникает ошибка компиляции. Более простые функционалы можно объединять в более сложные. Концептуально примерно так:

auto f = combine(
   [](int i) { std::cout << i << " | "; },
   [](const std::string& s) { std::cout << s << " | "; },
   [](int i, const std::string& s) { std::cout << i, " " << s << " | "; },
   [](const std::string& s, double d) { std::cout << s << " " << d; }
);

f("Hello", 3.14, 42); // -> 42 | Hello | 42 Hello | Hello 3.14

f(3.14, 42); // -> error: could not find actual parameter convertible to const std::string&


На базе такого механизма очень быстро и легко разрабатываются специфические DSL, которые делают разработку в любой прикладной области декларативной и очень наглядной, Получается как бы язык в языке. Правда, пока это используется только для разработки юнит тестов, но в принцие, область применения ни чем не ограничена. Код утилиты не выкладываю, во-первых, потому, что это более 300 строк кода, а во-вторых потому, что она давно уже перестала быть моей собственностью.