0

Sorry for being vague with my question, but I just don't understand what does this function does and how. Code from here:

template<typename ... T>
auto sum (T ... t)
{
    typename std::common_type<T...>::type result{}; //zero-initialization?
    (void)std::initializer_list<int>{(result += t, 0)...}; //why 0 is here
    return result;
}

I don't know why but this piece of code seems so odd, it don't look like C++ to me. Semantically, this function sums all the parameters in a result variable, obviously. But I completely do not understand why it was written that way. Using initializer_list here seem like a trick to trigger iteration over arguments in parameter pack but still...

Why initializer_list is explicitly was cast to void? To not take up extra memory?

And how iteration over parameter pack is going? Why not for example (void)std::initializer_list<int>{(result += t)...}; (it does not compile by the way).

Learpcs
  • 282
  • 3
  • 10
  • 2
    This trick was common before [fold expressions](https://en.cppreference.com/w/cpp/language/fold) were invented in C++17. Nowadays, you can just write `return (... + t);` Before that, pack expansion could only appear in certain contexts, e.g. in a brace-init list. So to perform calculations over a pack, you arranged a dummy brace-init list where each initializer had a side effect you wanted. The value of the initializer doesn't matter, only its side effect. `(result += t, 0)` uses a comma operator - it says "evaluate `result += t`, then produce integer `0` as the value". – Igor Tandetnik Dec 20 '21 at 14:33
  • 2
    cast to `void` was to avoid warning for some compilers for unused expression. – Jarod42 Dec 20 '21 at 14:38
  • `std::initializer_list{(result += t)...};` doesn't compile presumably because `(result += t)` is not of type `int` or convertible to `int`. In contrast, the type of `(result += t, 0)` is always the type of `0`, which is `int`. – Igor Tandetnik Dec 20 '21 at 14:41

1 Answers1

0

Thanks to the comments, I figured out the answer.

I haven't ever come across comma operator, so the line (result += t, 0) made to me no sense until your comments about EXISTENCE of comma operator and this question. So basically we initializing our list with zeros. And since I made type of initializer_list for integers, I can't write (void)std::initializer_list<int>{result += t...}, since returning value of result += t is int& not int.

So why don't we write (void)std::initializer_list<int&>{result += t...}? It doesn't compile, and I suspect that because array of references is forbidden in C++. So here's the solution to my problem:

template <typename ... T>
auto sum1(T ... t)
{
    std::common_type_t<T...> tmp{};
    std::initializer_list<std::reference_wrapper<std::common_type_t<T...>>>{tmp += t...};
    return tmp;
}
Learpcs
  • 282
  • 3
  • 10
  • *"I can't write ... since returning value of result += t is `int&` not `int`"* no, you can write that, at least if the `result` is of type `int`. *"So here's the solution to my problem"* Solution to what problem? Doesn't the code in the question work? – HolyBlackCat Dec 20 '21 at 20:22