Proposed resolution, February, 2018: Change 7.6.1.3 [expr.call] paragraph 4 as follows: When a function is called, each parameter (9.3.4.6 [dcl.fct])
—end example] If the function is a non-static
member function, the this parameter of the function
(_N4868_.11.4.3.2 [class.this]) Change 9.3.4.7 [dcl.fct.default] paragraph 1 as follows: Change 9.3.4.7 [dcl.fct.default] paragraph 4 as follows: For non-template functions, default arguments can be added in later
declarations of a function in the same scope. Declarations in different
scopes have completely distinct sets of default arguments. That is,
declarations in inner scopes do not acquire default arguments from
declarations in outer scopes, and vice versa. In a given function
declaration, each parameter subsequent to a parameter with a default
argument shall have a default argument supplied in this or a previous
declaration, unless the parameter was expanded from a parameter
pack, or shall be a function parameter pack. A default argument
shall not be redefined by a later declaration (not even to the same
value). [Example:
shall be is initialized (9.5 [dcl.init],
11.4.5.3 [class.copy.ctor], 11.4.5 [class.ctor]) with its
corresponding argument. If there is no corresponding argument, the default argument for the parameter is used; the program is ill-formed if one is not present. [Example:
template<typename ...T> int f(int n = 0, T ...t);
int x = f<int>(); // error: no argument for second function parameter
shall be is
initialized with a pointer to the object of the call, converted as if by an
explicit type conversion (7.6.3 [expr.cast]). [Note: There is
no access or ambiguity checking...
If an initializer-clause is specified in
a parameter-declaration this initializer-clause is used as a
default argument. [Note: Default arguments will be used
in calls where trailing arguments are
missing (7.6.1.3 [expr.call]). —end
note]
void g(int = 0, ...); // OK, ellipsis is not a parameter so it can follow
// a parameter with a default argument
void f(int, int);
void f(int, int = 7);
void h() {
f(3); // OK, calls f(3, 7)
void f(int = 1, int); // error: does not use default from surrounding scope
}
void m() {
void f(int, int); // has no defaults
f(4); // error: wrong number of arguments
void f(int, int = 5); // OK
f(4); // OK, calls f(4, 5);
void f(int, int = 5); // error: cannot redefine, even to same value
}
void n() {
f(6); // OK, calls f(6, 7)
}
template<class ... T> struct C {
void f(int n = 0, T...);
};
C<int> c; // OK; instantiates declaration void C::f(int n = 0, int)
[Accepted as a DR at the June, 2018 (Rapperswil) meeting.] The resolution of issue 777 attempts to
make this valid: However, it fails to do so, since any parameters resulting from the
expansion of the pack would be ordinary parameters without default
arguments following a parameter with a default argument, which is
ill-formed. Thus only an empty pack would be usable with such a
declaration, which violates the restriction against such contexts in
13.8 [temp.res] bullet 8.3.
template<typename ...T> void f(int n = 0, T ...t);