This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 110b. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2023-01-15


696. Use of block-scope constants in local classes

Section: 11.6  [class.local]     Status: C++11     Submitter: Steve Adamczyk     Date: 29 May, 2008

[Voted into the WP at the March, 2011 meeting.]

According to 11.6 [class.local] paragraph 1,

Declarations in a local class can use only type names, static variables, extern variables and functions, and enumerators from the enclosing scope.

This would presumably make both of the members of S2 below ill-formed:

    void test () {
      const int local_const = 7;
      struct S2 {
        int member:local_const;
        void f() { int j = local_const; }
      };
    }

Should there be an exception to this rule for constant values? Current implementations seem to accept the reference to local_const in the bit-field declaration but not in the member function definition. Should they be the same or different?

Notes from the September, 2008 meeting:

The CWG agreed that both uses of local_const in the example above should be accepted. The intent of the restriction was to avoid the need to pass a frame pointer into local class member functions, so uses of local const variables as values should be permitted.

Notes from the October, 2009 meeting:

There was interest in an approach that would allow explicitly-captured constants to appear in constant expressions but also to be “used.” Another suggestion was to have variables captured if they appear in either “use” or “non-use” contexts.

Proposed resolution (February, 2011):

  1. Change 7.5.5 [expr.prim.lambda] paragraph 17 as follows:

  2. Every id-expression that is an odr-use (6.3 [basic.def.odr]) of an entity captured by copy is transformed into an access to the corresponding unnamed data member of the closure type. [Note: an id-expression that is not an odr-use refers to the original entity, never to a member of the closure type. Furthermore, such an id-expression does not cause the implicit capture of the entity. —end note] If this is captured, each odr-use of this is transformed into an access to the corresponding unnamed data member of the closure type, cast (7.6.3 [expr.cast]) to the type of this. [Note: the cast ensures that the transformed expression is a prvalue. —end note] [Example:

      void f(const int*);
      void g() {
        const int N = 10;
        [=] {
          int arr[N];    // OK: not an odr-use, refers to automatic variable
          f(&N);         // OK: causes N to be captured; &N points to the
                         // corresponding member of the closure type
        }
      }
    

    end example]

  3. Change 11.6 [class.local] paragraph 1 as follows:
  4. ...Declarations in a local class can use only type names, static variables, extern variables and functions, and enumerators from the shall not odr-use (6.3 [basic.def.odr]) a variable with automatic storage duration from an enclosing scope. [Example:

      int x;
      void f() {
        static int s ;
        int x;
        const int N = 5;
        extern int g q();
    
        struct local {
          int g() { return x; }     // error: odr-use of automatic variable x has automatic storage duration
          int h() { return s; }     // OK
          int k() { return ::x; }   // OK
          int l() { return g q(); } // OK
          int m() { return N; }     // OK: not an odr-use
          int* n() { return &N; }   // error: odr-use of automatic variable N
        };
      }
    
      local* p = 0;                 // error: local not in scope
    

    end example]