When are default arguments parsed?
Section [dcl.fct.default]
Nathan Sidwell

Created on 2001-11-27.00:00:00 last changed 2 months ago


Date: 2020-11-15.00:00:00

Additional note (November, 2020):

Paper P1787R6, adopted at the November, 2020 meeting, partially addresses this issue.

Date: 2012-02-15.00:00:00

Notes from the February, 2012 meeting:

It was decided to handle the question of parsing an initializer like T<a,b>(c) (a template-id or two declarators) in this issue and the remaining questions in issue 361. For this issue, a template-id will only be recognized if there is a preceding declaration of a template.

Date: 2011-08-15.00:00:00

Additional notes (August, 2011):

See also issues 1352 and 361.

Date: 2011-08-15.00:00:00

Notes from the August, 2011 meeting:

In addition to default arguments, commas in template argument lists also cause problems in initializers for nonstatic data members:

    struct S {
      int n = T<a,b>(c);  // ill-formed declarator for member b
                          // or template argument?

(This is from #16 of the IssuesFoundImplementingC0x.pdf document on the Bloomington wiki.

Date: 2009-06-19.00:00:00

Additional notes, May, 2009:

Presumably the following is ill-formed:

    int f(int = f());

However, it is not clear what in the Standard makes it so. Perhaps there needs to be a statement to the effect that a default argument only becomes usable after the complete declarator of which it is a part.

Date: 2005-10-15.00:00:00

Notes from the October, 2005 meeting:

The CWG agreed that the first example (A) is currently well-formed and that it is not unreasonable to expect implementations to handle it by processing default arguments recursively.

Date: 2003-09-19.00:00:00

The standard is not precise enough about when the default arguments of member functions are parsed. This leads to confusion over whether certain constructs are legal or not, and the validity of certain compiler implementation algorithms. [dcl.fct.default] paragraph 5 says "names in the expression are bound, and the semantic constraints are checked, at the point where the default argument expression appears"

However, further on at paragraph 9 in the same section there is an example, where the salient parts are

  int b;
  class X {
    int mem2 (int i = b); // OK use X::b
    static int b;
which appears to contradict the former constraint. At the point the default argument expression appears in the definition of X, X::b has not been declared, so one would expect ::b to be bound. This of course appears to violate 6.4.6 [basic.scope.class] paragraph 1(2) "A name N used in a class S shall refer to the same declaration in its context and when reevaluated in the complete scope of S. No diagnostic is required."

Furthermore 6.4.6 [basic.scope.class] paragraph 1(1) gives the scope of names declared in class to "consist not only of the declarative region following the name's declarator, but also of .. default arguments ...". Thus implying that X::b is in scope in the default argument of X::mem2 previously.

That previous paragraph hints at an implementation technique of saving the token stream of a default argument expression and parsing it at the end of the class definition (much like the bodies of functions defined in the class). This is a technique employed by GCC and, from its behaviour, in the EDG front end. The standard leaves two things unspecified. Firstly, is a default argument expression permitted to call a static member function declared later in the class in such a way as to require evaluation of that function's default arguments? I.e. is the following well formed?

  class A {
    static int Foo (int i = Baz ());
    static int Baz (int i = Bar ());
    static int Bar (int i = 5);
If that is well formed, at what point does the non-sensicalness of
  class B {
    static int Foo (int i = Baz ());
    static int Baz (int i = Foo());
become detected? Is it when B is complete? Is it when B::Foo or B::Baz is called in such a way to require default argument expansion? Or is no diagnostic required?

The other problem is with collecting the tokens that form the default argument expression. Default arguments which contain template-ids with more than one parameter present a difficulty in determining when the default argument finishes. Consider,

  template <int A, typename B> struct T { static int i;};
  class C {
    int Foo (int i = T<1, int>::i);
The default argument contains a non-parenthesized comma. Is it required that this comma is seen as part of the default argument expression and not the beginning of another of argument declaration? To accept this as part of the default argument would require name lookup of T (to determine that the '<' was part of a template argument list and not a less-than operator) before C is complete. Furthermore, the more pathological
  class D {
    int Foo (int i = T<1, int>::i);
    template <int A, typename B> struct T {static int i;};
would be very hard to accept. Even though T is declared after Foo, T is in scope within Foo's default argument expression.

Suggested resolution:

Append the following text to [dcl.fct.default] paragraph 8.

The default argument expression of a member function declared in the class definition consists of the sequence of tokens up until the next non-parenthesized, non-bracketed comma or close parenthesis. Furthermore such default argument expressions shall not require evaluation of a default argument of a function declared later in the class.

This would make the above A, B, C and D ill formed and is in line with the existing compiler practice that I am aware of.

Date User Action Args
2020-12-15 00:00:00adminsetmessages: + msg6239
2012-02-27 00:00:00adminsetmessages: + msg3767
2012-02-27 00:00:00adminsetstatus: open -> drafting
2011-09-06 00:00:00adminsetmessages: + msg3561
2011-09-06 00:00:00adminsetmessages: + msg3560
2009-06-19 00:00:00adminsetmessages: + msg2081
2005-10-22 00:00:00adminsetmessages: + msg1263
2001-11-27 00:00:00admincreate