Solution

Let’s first define what is our goal. We want to write a template function which will behave like std::transform , but be able to take an unlimited number of input range beginnings after 2nd and before last 2 parameters. For example:

Instead of implementing this algorithm from scratch let’s implement the existing second overload from the STL, then we’ll improve it.

It’s pretty easy to add the support of a third input range.

What if we make use of template parameter packs and instead of the second range have any number of ranges, something like this:

Nice and easy right? It won’t compile. InputIters … first parameter(s) can’t be in the middle.

That’s a big problem. It means there is no way our function can have the desired signature. But it doesn’t mean we can’t support the desired usage. We wouldn’t have this problem if the well-known signature of std::transform was a bit different:

There’s a simple reason why it’s not: it’s hugging ugly. But no doubt, it’s easy to extend:

This both compiles and works fine, it’s just ugly. How about we make it even uglier and put a makeup on it? Let’s first rename it to __transform_impl .

Now, the makeup. It’s a function which will support our desired signature and call __transform_impl underneath.

As we can see, the return type is not certain anymore. Lucky for us, this function is going to have one and only return statement, so we can simply write decltype(auto) and let compiler deal with it. But what if it wasn’t this easy? What if we were forced to specify the type? We know that OutputIter type is the penultimate one in the parameter pack InputIters_OutputIter_Function . This is how we get it from the pack.

But, as already mentioned, in this particular case we are fine with decltype(auto) .

Now, we have to rearrange arguments to call __transform_impl , more specifically, we need to move the last two of those to the beginning, right after the first two parameters ( first and last ). And we’ll do it using std::tuple . First, we’ll make a tuple from the pack, then extract the last two elements from it:

Note, that we called __transform_helper , not __transform_impl . We added this middle level to make use of std::make_index_sequence .

So we needed it to get all the elements from the tuple except the last two.

That’s it. Here is the link to my GitHub repository. I’ll be happy to see corrections and improvements in the comments bellow.