p0478r0
Template argument deduction for non-terminal function parameter packs

Published Proposal,

This version:
wg21.tartanllama.xyz/partial-ordering
Authors:
Audience:
EWG
Project:
ISO JTC1/SC22/WG21: Programming Language C++

Abstract

This proposal aims to add support for non-terminal function parameter pack template argument deduction to the C++ language. There is a companion paper P0485 that amends rules for partial ordering of function templates which enables overload syntax, which resolves CWG1825.

1. Motivation and scope

Function parameter packs are a great tool for generic programming. However, some of their possible applications are constrained by the fact that packs can undergo template argument deduction only if they appear as the last parameter of the function template parameter list (or if every subsequent parameter has a default argument).

This limits the freedom of library interfaces of choosing the order of function parameters, which may lead to inconsistencies if a variadic overload of an already existing function or a variadic overload with an additional parameter is desired to be added, forcing a change of the order of the parameters in order to support the functionality.

template<class Variant, class... Callables>
inplace_visit(Variant&& variant, Callable&&... callables);
// Variant(s) last in std::visit, but first in hypothetical std::inplace_visit

Sometimes it may be convenient to directly access the last elements of the function parameter list:

template <class... Args, class Last>
void signal(Args... args, Last last)
{
// callback expects 5 arguments, and we only want to pass it the first 5
if constexpr(sizeof... (Args) > 5) {
return signal(args...);
} else if constexpr (sizeof... (Args) == 4) {
callback(args..., last);
} else {
callback(args...);
}
}
template <class First, class... Middle, class Last>
auto alternate_tuple(First first, Middle... middle, Last last)
{
if constexpr (sizeof... (middle) <= 2) {
return std::tuple(first, last, middle...);
} else {
return std::tuple_cat(std::tuple(first, last), alternate_tuple(middle...));
}
}

2. Proposal

We propose that if exactly one function parameter pack is present in a function template for which explicit template arguments are not provided, such parameter pack would only be deduced to correspond to exactly the number of arguments such that the call to the variadic function is valid.

[Example

template <class A, class... B, class C> void foo(A a, B... b, C c);
foo(1, 2, 3, 4); // b is deduced as [2, 3]

-End example]

3. Interaction with the language

3.1. Default arguments

Currently C++ already supports default arguments before and, according to CWG 1609, after a parameter pack. Nothing would change.

3.2. Default template arguments

Default template arguments are already allowed after a parameter pack. There would be no semantic difference.

3.3. Overload resolution

This is dealt with by another proposal on partial ordering and transformed templates (P0485) which resolves CWG 1825, and would easily enable overloading by applying the same proposed rules of replacing the pack in the deduced context with N invented types.

This may alter the behavior of a call to the following set of function templates

template<class T, class... Args>
void foo(T, int, Args);
template<class... Args>
void foo(Args, int, int);

Today foo(1, 2, 3) unambiguously calls the first overload. By allowing deduction for the second version, the latter becomes the more specialized overload.

However, variadic overloads with non-terminal parameter packs do not seem to be common practice, and believe that the utility of this proposal outweighs this obscure breaking change.

4. Implementation experience

We have found no particular difficulty with creating an experimental implementation of the proposal, which is available at https://github.com/bmanga/clang.

Standarese Wording available on request.

5. Alternatives

Currently, the workarounds for accessing the last elements of a variadic function template usually involves tuple manipulations and use of std::index_sequence, at the cost of increased complexity. Future proposals on parameter pack indexing may also help alleviate the problems.

We are still however convinced that it would make code cleaner and more uniform to lift the current arbitrary restriction on the function parameter pack position.

6. References

CWG 1609: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1609

CWG 1825: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1825

P0485: Amended rules for Partial Ordering of function templates

7. Acknowledgement

We like to thank Gordon Brown for his review and suggestions.