Что является хорошей альтернативой этому C ++ 17 кратному выражению в C ++ 14? - PullRequest
0 голосов
/ 24 июня 2018

Вот хорошая, краткая лямбда-выражения на основе сгиба в C ++ 17:

#include <cstdint>

using ::std::uint64_t;

constexpr auto sumsquares = [](auto... n) { return ((n * n) + ...); };

// I want this to work.
uint64_t foo(uint64_t x, uint64_t y, uint64_t z)
{
    return sumsquares(x, y, z);
}
// And this too
double bar(uint64_t x, double y)
{
    return sumsquares(x, y);
}

У меня есть этот код, который я написал, чтобы сделать что-то похожее в C ++ 14, но кажется, чтонамного более многословно и запутанно, чем должно быть.Я ищу способ выразить вышеупомянутый код C ++ 17 в C ++ 14 относительно ясным и лаконичным способом.Чтобы быть точным, я хочу иметь возможность писать код, который вычисляет квадрат величины вектора для вектора некоторого известного числа измерений с синтаксисом вызова функции.Количество измерений может варьироваться произвольно.И точный числовой тип отдельных компонентов системы координат также может быть произвольным и, возможно, неоднородным.Но общий способ обработки C ++ 17-кратных выражений в C ++ 14 был бы идеальным.

#include <cstdint>
#include <utility> 

using ::std::uint64_t;

namespace {
    static constexpr struct {
        template <typename T>
        auto operator()(T && n) const
        {
           return n*n;
        }
        template <typename T, typename... S>
        auto operator()(T && n, S && ... s) const
        {
            return (n * n) + (*this)(::std::forward<S>(s)...);
        }
    } sumsquares;
}

// I want this to work.
uint64_t foo(uint64_t x, uint64_t y, uint64_t z)
{
    return sumsquares(x, y, z);
}
// And this too
double bar(uint64_t x, double y)
{
    return sumsquares(x, y);
}

Ответы [ 3 ]

0 голосов
/ 24 июня 2018

Возможный нерекурсивный способ записи sum() следующий

template <typename ... Ts>
auto sum (Ts ... ts)
 {
   using unused = int[];

   std::common_type_t<Ts...>  ret {};

   (void)unused{ 0, (ret += ts, 0)... };

   return ret;
 }

С учетом функции sum(), sum_of_squares() можно просто записать следующим образом

template <typename ... Ts>
auto sum_of_squares (Ts ... ts)
 { return sum( (ts*ts)... ); }
0 голосов
/ 24 июня 2018
#include <utility>
#include <functional>

template<class F, class A0>
auto fold(F&&, A0&& a0) {
    return std::forward<A0>(a0);
}

template<class F, class A0, class...As>
auto fold(F&& f, A0&&a0, As&&...as) {
    return f(std::forward<A0>(a0), fold(f, std::forward<As>(as)...));
}

auto sum_squares=[](auto&&...args) {
    return fold(std::plus<>{}, (args * args)... );
};
0 голосов
/ 24 июня 2018

Да, на самом деле вы можете сделать более простую и более общую задачу, определив общую сумму для нескольких объектов:

template<typename T>
T sum(T x)
{
    return x;
}
template<typename U, typename... T>
auto sum(U x, T... nums)
{
    return x + sum(nums...);
}

template<typename... T>
auto sum_of_squares(T... nums)
{
    auto square = [](auto x) { return x * x; };
    return sum(square(nums)...);
}

Демо здесь , а здесь вы можете увидеть сгенерированную сборку (что кажется оптимальным). Хотя мне лично очень не нравится auto в качестве возвращаемого типа, здесь он позволяет избежать очень сложного выражения для получения типа.

...