16

Yes, I can use std::initializer_list. Yes, even easier, I can do aggregate initialization. But how does this work? I can't seem to fold my head around C++17's fold expressions. There aren't enough examples out there.

Here's what I came up with:

template<class T, std::size_t N>
struct foo
{
    T arr[N];

    template<typename... Args>
    constexpr foo(Args&&... pack)
    {
        static_assert(sizeof...(pack) <= N, "Too many args");
        std::size_t i = 0;
        (arr[i++] = ...);
    }
};

int main()
{
    foo<int, 5> a(1, 2, 3, 4, 5);
}

EDIT: Compiling with latest Clang. Fold expressions are supported.

Live example: http://coliru.stacked-crooked.com/a/777dc32da6c54892

Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196
DeiDei
  • 10,205
  • 6
  • 55
  • 80

2 Answers2

14

You need to fold with the comma operator, which also solves the sequencing problem.

(void(arr[i++] = pack) , ...);
T.C.
  • 133,968
  • 17
  • 288
  • 421
  • 2
    Yeah, works perfectly. It's gonna take some time before this syntax becomes not confusing to me. It looks perfectly logical when someone else writes it. :D – DeiDei Jan 02 '16 at 19:07
  • 1
    @Jarod42 Nope, `,` handles sequencing. – T.C. Jan 02 '16 at 19:20
5

Since the comma operator is left-associative, you would ideally use a left unary fold:

(...,void(arr[i++] = pack))

The cast to void is to make sure that the built-in comma operator is used. In this case, the handedness doesn't actually matter.

Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132