Упаковка, распаковка и сохранение пакета параметров в кортеже

У меня есть указатель функции и параметры, и я хотел бы сохранить их и, возможно, изменить их и вызвать с их помощью функцию.

Я видел части этого ответа, однако я не уверен, как будет выглядеть полное решение, прошу прощения, но я не совсем понимаю пакеты параметров и то, как они связаны с кортежем.

Вот фрагменты моего кода, которые я пытаюсь заставить работать вместе:

У меня есть это, по сути, просто вызов функции, я думаю, что это можно использовать для сохранения вызова в «вызываемой» структуре, чтобы создать интерфейс.

из этого вопроса: Вызов универсальной функции C++ с параметром varargs

template<typename R, typename... Args>
auto call(R(*function)(Args...), Args... args) -> typename std::enable_if<!std::is_same<R, void>::value, R>::type 
{
    return function(args...);
}

template<typename... Args>
void call(void (*function)(Args...), Args... args)
{
    function(args...);
}

Эта структура должна хранить параметры и указатель на функцию. (спасибо RaymondChen за подсказку, как должно быть правильно)

template<typename R, typename... Args>
struct callable
{
    R(*function)(Args...);
    std::tuple<Args...> params;

    callable(Args... argv):
    params(std::make_tuple(argv...))
    {}

    // .....
};

Я до сих пор не знаю, как вызвать функцию с помощью std::tuple. Насколько я понимаю, мне нужно каким-то образом вернуть кортеж обратно в Args..., а затем вызвать его.

**Чего я пытаюсь достичь:

  • Сохраните вызов, чтобы использовать его позже
  • Создайте мой вызов и заполните его своими параметрами из работающего приложения.
  • Считайте сохраненные параметры, чтобы выполнить какую-либо отладку.**

Все еще неясно, что вы пытаетесь сделать, поскольку std::apply(argv, params) не имеет смысла. Член params пока ничего не содержит.) Создается ли вызываемая поддержка для вызова функции или просто для сохранения параметров? Если экономите, то callable(Args...argv) : params(std::make_tuple(argv...)) {}

Raymond Chen 02.07.2024 00:25

Как вы хотите использовать callable? Рэймонд показал, как хранить argv в params. Как вы собираетесь использовать вызываемую функцию?

NathanOliver 02.07.2024 00:37

@NathanOliver Я бы хотел просто вызвать функцию, которая возвращает тип функции, но не имеет параметров, как в callable, например auto call(), или, возможно, с void* в качестве типа возвращаемого значения, которая затем будет вызывать callable->function. Я не знаю, как бы я применил параметры.

LemonJumps 02.07.2024 00:51

Я понял это, это буквально std::apply(function, params) последний кусочек головоломки - создать конструктор, который принимает только указатель на функцию, чтобы я мог самостоятельно предоставить параметры. Или, возможно, мне следует разделить параметры и указатель функции и сохранять параметры только тогда, когда это действительно необходимо.

LemonJumps 02.07.2024 01:26

Разве std::function достаточно/проще?

Jarod42 02.07.2024 14:53

@Jarod42 нет, хотя здесь все находится в небольшой структуре, в моем окончательном коде указатели и параметры fn хранятся отдельно в векторах. Это сделано для целей согласованности кэша, а также для того, чтобы я мог читать/повторно использовать/изменять параметры для оптимизации «точно в срок».

LemonJumps 03.07.2024 09:41
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
98
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Если вы начали хранить функцию и необходимые для нее параметры в Callable, я бы предложил просто предоставить перегрузку operator() для вызова Callable с ее сохраненными параметрами.

Что-то в этом роде:

// Functor to store the function and its parameters
template<typename R, typename... Args>
class Callable /* final */
{
    R(*mFuncPtr)(Args...) { nullptr };  //  function pointer.
    std::tuple<Args...> mParams{};      //  store the parameters as std::tuple

public:
    explicit constexpr Callable(R(*func)(Args...))
        : mFuncPtr{ func } {}

    explicit constexpr Callable(R(*func)(Args...), Args&&... argv)
        : mFuncPtr{ func }
        , mParams{ std::make_tuple(std::forward<Args>(argv)...) } {}

    // optional setter for mParams
    void set(Args&&... argv)
    {
        mParams = std::make_tuple(std::forward<Args>(argv)...);
    }

    auto operator()() -> std::conditional_t<std::is_void_v<R>, void*, R>
    {
        if constexpr (std::is_void_v<R>) 
        {  
            // invoke the function pointer with tuple pack. 
            std::apply(mFuncPtr, mParams);
            return nullptr;     // Use nullptr for void return type
        }
        else 
        {
            return std::apply(mFuncPtr, mParams);;
        }
    }

    // Print the stored parameters
    void printParams() const
    {
        std::cout << "(";
        printParamsImpl(std::index_sequence_for<Args...>{});
        std::cout << ")\n";
    }

private:
    template<std::size_t... I>
    void printParamsImpl(std::index_sequence<I...>) const
    {
        (..., (std::cout << (I == 0 ? "" : ", ") << std::get<I>(mParams)));
    }
};

(Посмотрите демо-версию живого примера)

Мне нравится, что вам не нужно явно указывать типы шаблонов, однако это не работает, когда функция void fn(void) Я изменил пример, чтобы выделить его: пример Я думаю, что type_traits может помочь с этим, но я не конечно, как я мог бы это использовать, возможно, может быть специализация с нулевым параметром?

LemonJumps 02.07.2024 01:46

@LemonJumps В этом случае вам следует запретить создание экземпляра параметризованного конструктора, который имеет Args... от SFINE: gcc.godbolt.org/z/sjh5r3rPY

JeJo 02.07.2024 08:05

почему вы возвращаете ноль void* в случае void? Вы можете return std::apply(mFuncPtr, mParams); безоговорочно: «В функции, возвращающей (возможно, с указанием cv) void, можно использовать оператор return с выражением, если тип выражения (возможно, с указанием cv) void». en.cppreference.com/w/cpp/language/return

Caleth 02.07.2024 11:28

@Caleth Как упомянул ОП в комментарии под сообщением: «[...] например auto call() или, возможно, с void* в качестве возвращаемого типа, который затем будет вызывать callable->function [...]». Я предполагаю, что тогда он/она имел в виду то, что я написал, что, кстати, тоже было принято. Почему он/она так хочет... это другой вопрос!

JeJo 02.07.2024 12:07

Опять же, я должен сказать, что меньше значит больше. Библиотечная функция std::bind уже довольно эффективно решает эту проблему:

template<typename... Args>
//requires sizeof...(Args) > 1
using Callable = decltype(std::bind(std::declval<Args>()...);

Callable c = std::bind(&foo::x,y,z,w);
auto res = c();

Чтобы еще больше усилить дизайн, добавьте std::function в свой микс:

template<typename R,typename... Args>
using Call_in = Callable<std::function<R(Args...)>, Args...>;

Call_in ci=std::bind(std::function<foo(bar)>{&bar::x}, bar{});
foo resi = ci();

Этот более динамичен; он может ввести стереть аргумент функции [объект], чтобы все функции с похожей сигнатурой вызова могли быть сохранены с использованием одной и той же специализации.

Как это позволит мне считывать определенные значения из параметров? Как это позволяет мне отделить указатель функции от параметров? Для моего варианта использования мне нужен доступ к этим данным, насколько я понимаю, std::bind не позволяет вам это сделать.

LemonJumps 03.07.2024 09:24

@LemonJumps, если это так, зачем беспокоиться об инкапсуляции и конструкторах? template<typename R,typename ...A> struct voidfn{ std::function<R(A...)> fn; std::tuple<A...> args; auto operator() { return std::apply(fn,args); }; }; Теперь его можно просто инициализировать как агрегат. И все в открытом доступе.

Red.Wave 03.07.2024 09:36

Другие вопросы по теме