8

I would like to write a sum function with variable number of argument with the condition that it should ignore argument that are not std::is_arithmetic

I have figured out a recursive version that works

auto old_sum(){
    return 0;
}

template<typename T1, typename... T>
auto old_sum(T1 s, T... ts){
    if constexpr(std::is_arithmetic_v<T1>)
        return s + old_sum(ts...);
    else
        return old_sum(ts...);
}

I am wondering if I can use the if constexpr in the context of fold expression to make the following code only considers arithmetic types from the argument pack:

template<typename... T>
auto fold_sum(T... s){
    return (... + s);
}
max66
  • 65,235
  • 10
  • 71
  • 111
motam79
  • 3,542
  • 5
  • 34
  • 60

2 Answers2

12

As we do not have a ternary constexpr operator, we can use a lambda instead.

#include <type_traits>

template<typename... T>
constexpr auto fold_sum(T... s){
    return (... + [](auto x)
    {
        if constexpr(std::is_arithmetic_v<T>) return x;
        else return 0;
    }(s));
}

Usage:

int main()
{
    static_assert(fold_sum(0, nullptr, 5, nullptr, 11, nullptr) == 16);
}

live example on godbolt.org

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • You should give the fold the identity of the sum to handle empty pack. – Jans Dec 14 '18 at 17:58
  • 3
    Would be quite a bit easier to read if you named the lambda ;-) – Barry Dec 14 '18 at 18:11
  • Is the `else` really necessary here? I can't imagine `if constexpr` would allow for a way to write unreachable code if intentionally misused. – 303 Oct 27 '21 at 17:48
3

You absolutely want to use if constexpr?

I propose a different alternative: std::get() and std::pair to simulate a constexpr ternary operator as follows (with a Vittorio Romeo's improvement; thanks)

#include <utility>
#include <type_traits>

template<typename ... Ts>
constexpr auto fold_sum (Ts const & ... s)
 { return (... + std::get<std::is_arithmetic_v<Ts>>(std::pair{0, s})); }

int main ()
 {
   static_assert(fold_sum(0, nullptr, 5, nullptr, 11, nullptr) == 16);
 }
max66
  • 65,235
  • 10
  • 71
  • 111