Calling a function using a variadic parameter pack

Is it possible to call a function with a parameter pack? Here's what I'm trying to do:

func magic<each T, U>(_ inputs: repeat each T, transform: (repeat each T)->U) -> U {
  // error: Cannot pass value pack expansion to non-pack parameter of type 'repeat each T'
  return transform(inputs)
}

let x = magic(1) { $0 * 2 }
let y = magic(1, 2, 3) { $0 * $1 + $2 }

func middleValue(a: Int, b: Int, c: Int) -> Int {
  return [a, b, c].sorted()[1]
}

let z = magic(14, 12, 5, transform: middleValue)

I want to take the pack of inputs and pass them as the various arguments of transform. Is there a way to do this?

2 Likes

Yes, it's quite easy actually. You just have to expand the parameter pack.

func magic<each T, U>(_ input: repeat each T, transform: (repeat each T)->U) -> U {
  return transform(repeat each input)
}

let x = magic(1) { $0 * 2 }
let y = magic(1, 2, 3) { $0 * $1 + $2 }

func middleValue(a: Int, b: Int, c: Int) -> Int {
  return [a, b, c].sorted()[1]
}

let z = magic(14, 12, 5, transform: middleValue)
1 Like

In fairness to @bjhomer, variadic generics are a bit unintuitive. I too looked at his example and couldn't immediately see why it didn't work, given it's obviously well-formed.

It's ironic that the compiler error message includes the magic string required to make this work - neatly quoted and everything! - yet is still inscrutable.

Yeah, I only got it right away because i'm used to C++ parameter packs. Where you have to return transform(std::forward<Input>(input)...); which is even less scrutible.

Edit: Yeah, you'd think that error message would include the fixit.

Ah, that makes sense. Thank you!