C ++ Преобразование кортежа однородного упакованного типа в кортеж необработанного типа - PullRequest
0 голосов
/ 23 января 2019

Я бы хотел вызвать std::apply() для функции;однако, я не могу, потому что std::tuple, который я использую, в настоящее время упакован.Например:

#include <tuple>

template <class T>
struct wrapped
{
    wrapped(T t) : t(t) {}

    T t;
};

template <class T, class ... Args>
struct delay_call
{
    T(*callback)(Args...);
    std::tuple<Args...> params;

    delay_call(T(*callback)(Args...), Args ... params) :
        callback(callback), params(params...)
    {}

    T call()
    {
        return std::apply(callback, params);
    }
};

template <class T, class ... Args>
struct delay_call_with_wrap
{
    T(*callback)(Args...);
    std::tuple<wrapped<Args>...> w_params;

    delay_call_with_wrap(T(*callback)(Args...), wrapped<Args> ... w_params) :
        callback(callback), w_params(w_params...)
    {}

    T call()
    {
        std::tuple<Args...> params; // = w_params.t
        return std::apply(callback, actual_params);
    }
};

float saxpy(float a, float x, float y)
{
    return a * x + y;
}

int main()
{
    float a = 1, x = 2, y = 3;
    delay_call delay_saxpy(saxpy, a, x, y);

    wrapped w_a = 1.f, w_x = 2.f, w_y = 3.f;
    delay_call_with_wrap w_delay_saxpy(saxpy, w_a, w_x, w_y);

    float result = delay_saxpy.call();

    float w_result = w_delay_saxpy.call();
}

структура delay_call работает должным образом;тем не менее, я не уверен, что делать с извлечением действительного значения каждого элемента кортежа и передачей его на std::apply() для выполнения.

Короче говоря, для delay_call_with_wrap::call, как бы я преобразовал std::tuple<wrapped<Args>...> вstd::tuple<Args...>

Ответы [ 3 ]

0 голосов
/ 23 января 2019

Вероятно, не лучшее решение для использования на практике, но вот то, где используется лямбда с переменным шаблоном, чтобы избежать index_sequence:

template <class T, class ... Args>
struct delay_call_with_wrap
{
    T(*callback)(Args...);
    std::tuple<wrapped<Args>...> w_params;

    delay_call_with_wrap(T(*callback)(Args...), wrapped<Args> ... w_params) :
        callback(callback), w_params(w_params...)
    {}

    T call()
    {
        auto helper = [this] <class ... Args_> (wrapped<Args_>... args)
        {
            return callback(args.t...);
        };
        return std::apply(helper, w_params);
    }
};

Демо

Идея состоит в том, чтобы просто предоставить функцию, которая соответствует аргументам, которые std::apply дает здесь - она ​​должна принимать wrapped<Args>....Оттуда тривиально расширить пакет при извлечении упакованного значения.

Мы используем лямбду, потому что std::apply хочет Callable, поэтому мы не можем просто использовать другую функцию-член.Ну, я думаю, мы могли бы перегрузить operator() для delay_call_with_wrap.Это было бы слегка запутанным, но, по крайней мере, не ограничивалось C ++ 2a (и отсутствующей поддержкой компилятора ), как шаблонными лямбдами.

0 голосов
/ 23 января 2019

Короче говоря, для delay_call_with_wrap::call, как бы я преобразовал std::tuple<wrapped<Args>...> в std::tuple<Args...>?

Мне кажется, лучше избегать std::apply(), используя старый способ std::make_index_sequence / std::index_sequence (см. Ответ HolyBlackCat).

Но, если вы действительно хотите использовать std::apply(), вы можете вызвать его первый раз, чтобы развернуть кортеж (чтобы получить кортеж развернутых значений), а затем вызвать как обычно.

Я имею в виду что-то как

T call ()
 {
   auto actual_params = std::apply([](auto ... wt){ return std::make_tuple(wt.t...); },
      w_params);
   return std::apply(callback, actual_params);
}

или, за один звонок, напрямую

T call()
 {
   return std::apply(callback,
             std::apply([](auto ... wt){ return std::make_tuple(wt.t...); },
                w_params));
 }

Это решение разумно, ИМХО, если член w_param является постоянным, так что вы можете вычислить actual_params один раз для всех и сделать его static

0 голосов
/ 23 января 2019

Я бы избежал std::apply полностью и вызвал бы callback напрямую, распаковав кортеж с помощью std::index_sequence:

template <std::size_t ...I> T call_low(std::index_sequence<I...>)
{
    return callback(std::get<I>(w_params).t...);
}

T call()
{
    return call_low(std::make_index_sequence<sizeof...(Args)>{});
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...