Arhn - архитектура программирования

Как продублировать расширение пакета параметров шаблона?

Рассмотрим этот код:

template < size_t... Indices >
void something(std::index_sequence<Indices...>)
{
  // how to obtain the following call where N is sizeof...(Indices)?
  // foo(f(0),g(0),f(1),g(1),...,f(N-1),g(N-1));
}

Ответы:


1

Ключ к ответу на вопрос типа:

// how to obtain the following call where N is sizeof...(Indices)?
// foo(f(0),g(0),f(1),g(1),...,f(N-1),g(N-1));

состоит в том, чтобы сформулировать, как на самом деле создать такое расширение пакета. У нас есть 2N аргументов, которые хотели бы:

+=====+======+
| idx | expr |
+-----+------+
|  0  | f(0) |
|  1  | g(0) |
|  2  | f(1) |
|  3  | g(1) |
|   ....
+=====+======+

В C++17 мы можем написать такое выражение с if constexpr:

template <size_t I>
auto expr() {
    if constexpr (I % 2 == 0) { 
        // even indices are fs
        return f(I / 2);
    } else {
        // odds are gs
        return g(I / 2);
    }
}

Это может быть даже лямбда, принимающая integral_constant в качестве аргумента. Таким образом, нам просто нужно превратить наши N аргументов в 2N аргументов, а это всего лишь вопрос добавления дополнительных индексов:

template <auto V>
using constant = std::integral_constant<decltype(V), V>;

template < size_t... Indices >
void something(std::index_sequence<Indices...>) {
    auto expr = [](auto I) {
        if constexpr (I % 2 == 0) {
            return f(I / 2);
        } else {
            return g(I / 2);
        }
    }

    return foo(
        expr(constant<Indices>{})...,                     // 0, ..., N-1
        expr(constant<Indices + sizeof...(Indices)>{})... // N, ..., 2N-1
    );
}
05.02.2018

2

Лучшее, что я могу себе представить, это использование std::tuple_cat и std::make_pair для создания std::tuple аргументов из foo().

К сожалению, я знаю, как это сделать только с помощью вспомогательной функции для вызова foo()

template <typename T, std::size_t... I>
void somethingH (T const & t, std::index_sequence<I...> const &)
 { foo(std::get<I>(t)...); }

template <std::size_t... I>
void something (std::index_sequence<I...> const &)
 {
   somethingH(std::tuple_cat(std::make_pair(f(I), g(I))...),
              std::make_index_sequence<(sizeof...(I) << 1)>{});
 }

Используя std::apply, доступный только начиная с C++17, вы можете использовать лямбда-функцию, чтобы выбрать правильный foo (как предложил SirGuy; спасибо!) и избежать вспомогательной функции

template <std::size_t... I>
void something (std::index_sequence<I...> const &)
 {
   std::apply([](auto && ... as)
                 { return foo(std::forward<decltype(as)>(as)...); },
              std::tuple_cat(std::make_pair(f(I), g(I))...));
 }

Ниже приведен полный рабочий пример C++17.

#include <iostream>
#include <utility>
#include <tuple>

int f (std::size_t n)
 { return n; }

int g (std::size_t n)
 { return -n; }

template <typename ... Args>
void foo (Args ... as)
 { (std::cout << ... << as) << std::endl; }

template <std::size_t... I>
void something (std::index_sequence<I...> const &)
 {
   std::apply([](auto && ... as)
                 { return foo(std::forward<decltype(as)>(as)...); },
              std::tuple_cat(std::make_pair(f(I), g(I))...));
 }

int main()
 {
   something(std::make_index_sequence<7U>{});
 }
03.02.2018
  • В версии std::apply почему бы просто не сделать лямбду вместо функции с именем getCorrectFoo? std::apply([](auto && ... args) { return foo(std::forward<decltype(args)>(args)...);}, t); 05.02.2018
  • @SirGuy - потому что я не привык к лямбда-функциям, как вы :( Очень хорошее улучшение; спасибо! 05.02.2018
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..