From [dcl.fct]/22:
An abbreviated function template is equivalent to a function template ([temp.fct]) whose template-parameter-list includes one invented type template-parameter for each generic parameter type placeholder of the function declaration, in order of appearance. [..] The invented type template-parameter is a template parameter pack if the corresponding parameter-declaration declares a function parameter pack.
Note that prefix<Is> auto...
is both a pack and a pack expansion simultaneously.
So the transformed template would look like
[] <prefix<Is>... Args> (Args..., auto arg, auto...) {
return arg;
}(args...)
Which is equivalent to
[] <typename... Args> requires(prefix<Args, Is> && ...) (Args..., auto arg, auto...) {
return arg;
}(args...)
(This still generates the same error message, too.)
Where we can see that 1) Args is in a non-deduced context and will always remain empty, and 2) Is
and Args
would have to agree in length for the constraint to be satisfiable.
The solution given in the comments is not ideal IMO, as creating a tuple is likely relatively expensive (especially at compile time). I think your solution + proper forwarding is the best for now (until we get proper pack subscripts). I.e. something like this:
template<std::size_t>
struct dummy { constexpr dummy(auto&&){}; };
template <std::size_t N, typename... Args>
constexpr decltype(auto) nth_element(Args&&... args) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>) -> decltype(auto) {
return [](dummy<Is> ..., auto&& arg, auto&&...) -> decltype(auto) { // OK // #2
return std::forward<decltype(arg)>(arg);
}(std::forward<Args>(args)...);
}(std::make_index_sequence<N>());
}
nth_element
can be replaced byreturn std::get<N>(std::tuple{args...});
. – Ostrom