1
4

3 回答 3

4

拥抱消极思维的力量,从零开始归纳:

auto sum(auto &&val, auto &&...vals) {
    if constexpr (sizeof...(vals) == 0)
        return val;
    else
        return val + sum(std::forward<decltype(vals)>(vals)...);  
}

sum(x)上面的定义具有现在将编译并返回的副作用x。(事实上​​,你甚至可以让函数在没有参数的情况下工作,方法是让它返回零,但随之而来的问题是:零是哪种类型的?为了避免不得不去那里,我没有定义这个案例。)如果你坚持sum仅从 arity 2 开始定义,您可以使用它来代替:

auto sum(auto &&val0, auto &&val1, auto &&...vals) {
    if constexpr (sizeof...(vals) == 0)
        return val0 + val1;
    else
        return val0 + sum(std::forward<decltype(val1)>(val1),
            std::forward<decltype(vals)>(vals)...);
}

但是,您可能应该在有意义的情况下允许“空”的情况:它使代码更简单、更通用。请注意,例如,在后一种定义中,加法运算符如何出现两次:这实际上是在两种情况之间重复了折叠逻辑(在这种情况下,它只是一次加法,所以它相对简单,但对于更复杂的操作,它可能会更繁重) ,而处理退化的情况通常是微不足道的,并且不会重复任何内容。

(我省略了概念注释,因为它们似乎与主要问题并不特别相关。)

于 2021-01-16T12:06:03.240 回答
3
template<class... Additive> decltype(auto) sum(Additive &&...val) {
    return (std::forward<Additive>(val) + ...);
}

?

题外话:不确定 Op 的真正需求,我不小心快速设计了一件我一直在想的东西,有时。:D

#include <iostream>
#include <functional>
#include <type_traits>

template<class... Fs> struct Overloads;

template<class F, class... Fs> struct Overloads<F, Fs...>: Overloads<Fs...> {
        using Fallback = Overloads<Fs...>;

        constexpr Overloads(F &&f, Fs &&...fs): Fallback(std::forward<Fs>(fs)...), f(std::forward<F>(f)) {}

        template<class... Args> constexpr decltype(auto) operator()(Args &&...args) const {
                if constexpr(std::is_invocable_v<F, Args...>) return std::invoke(f, std::forward<Args>(args)...);
                else return Fallback::operator()(std::forward<Args>(args)...);
        }
private:
        F f;
};

template<class... Fs> Overloads(Fs &&...fs) -> Overloads<Fs...>;

template<class F> struct Overloads<F> {
        constexpr Overloads(F &&f): f(std::forward<F>(f)) {}

        template<class... Args> constexpr decltype(auto) operator()(Args &&...args) const {
                return std::invoke(f, std::forward<Args>(args)...);
        }
private:
        F f;
};

template<> struct Overloads<> {
        template<class... Args> constexpr void operator()(Args &&...) const noexcept {}
};

constexpr int f(int x, int y) noexcept { return x + y; }

void g(int x) { std::cout << x << '\n'; }

template<class... Vals> decltype(auto) omg(Vals &&...vals) {
        static constexpr auto fg = Overloads(f, g);
        return fg(std::forward<Vals>(vals)...);
}

int main() {
        omg(omg(40, 2));
}

>_<

于 2021-01-16T11:44:27.480 回答
2

您可以将一个项目解压缩到一个变量中并使用它:

if constexpr (sizeof...(vals) == 1) {
    auto&& only_value(std::forward<decltype(vals)>(vals)...);
    return val + only_value;
}
于 2021-01-16T12:07:48.413 回答