Title
Function parameter packs following default arguments
Status
cd5
Section
9.3.4.7 [dcl.fct.default]
Submitter
Richard Smith

Created on 2016-02-25.00:00:00 last changed 7 months ago

Messages

Date: 2021-02-24.00:00:00

Proposed resolution, February, 2018:

  1. Change 7.6.1.3 [expr.call] paragraph 4 as follows:

  2. When a function is called, each parameter (9.3.4.6 [dcl.fct]) shall be is initialized (9.4 [dcl.init], _N4750_.15.8 [class.copy], 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
    

    end example] If the function is a non-static member function, the this parameter of the function (_N4868_.11.4.3.2 [class.this]) 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...

  3. Change 9.3.4.7 [dcl.fct.default] paragraph 1 as follows:

  4. 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]
  5. Change 9.3.4.7 [dcl.fct.default] paragraph 4 as follows:

  6. 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:

      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)
    
Date: 2018-06-15.00:00:00

[Accepted as a DR at the June, 2018 (Rapperswil) meeting.]

The resolution of issue 777 attempts to make this valid:

   template<typename ...T> void f(int n = 0, T ...t); 

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.

History
Date User Action Args
2020-12-15 00:00:00adminsetstatus: tentatively ready -> cd5
2018-02-27 00:00:00adminsetmessages: + msg5859
2018-02-27 00:00:00adminsetstatus: open -> tentatively ready
2016-02-25 00:00:00admincreate