Шаблон Variadic для получения ссылок на несколько контейнеров - PullRequest
0 голосов
/ 14 февраля 2019

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

Алгоритм, который я выполняю, в основном ведет себя как

const auto result = s0 + a1 * s1 + a2 * s2 + ...

Где все si являются контейнерами, содержащими все одинаковое количество элементов.Количество суммируемых элементов известно во время компиляции.

Функция, которую я ищу, должна вести себя так: (гипотетически)

inline Container sum(const Container& s0, double a1, const Container& s2, ....){
    auto result = Container(s0);
    for (int i = 0; i < result.size(); ++i)
        result[i] += a1 * s1[i] + a2 * s2[i] + ...;
    return result;
}

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

Весь код должен быть действительным C++ 11, у меня нет доступа к более современному компилятору в этом проекте.

1 Ответ

0 голосов
/ 14 февраля 2019

Я бы сгруппировал double и container, чтобы упростить код до:

template <typename C, typename ... Cs>
C sum(const C& c0, const Cs&... cs)
{
    auto result = c0;
    for (int i = 0; i < result.size(); ++i)
#if 0 // C++17
        result[i] += (cs[i] + ...); 
#else // C++11/C++14
        const int dummy[] = {0, (static_cast<void>(result[i] += cs[i]), 0)...};
        static_cast<void>(dummy); // avoid warning for unused variable.
#endif
    return result;
}

Итак, для группировки что-то вроде:

template <typename C>
struct MulContainer
{
    auto operator [](int i) const { return d * c[i]; }

    double d;
    const C& c;
};

Так что для вызова вместоиз

sum(c0, a1, c1, a2, c2);

у вас будет:

sum(c0, MulContainer{a1, c1}, MulContainer{a2, c2});

Если действительно необходимо, с std::index_sequence у вас все еще может быть синтаксис первого вызова.

template <typename C, std::size_t... Is, typename Tuple>
C sum_impl(const C& c0, std::index_sequence<Is...>, const Tuple& t)
{
    return sum(c0, MulContainer{std::get<2 * Is>(t), std::get<2 * Is + 1>(t)}...);
}

template <typename C, typename ... Ts>
C final_sum(const C& c0, const Ts&... ts)
{
    static_assert(sizeof...(Ts) % 2 == 0);
    return sum_impl(c0, std::make_index_sequence<sizeof...(Ts) / 2>{}, std::tie(ts...));
}

std::index_sequence это C ++ 14, но может быть реализовано в C ++ 11.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...