简体   繁体   中英

The code below doesn't compile. Maybe because GCC with std=c++2a is still not completely up to date with the most recent draft

[class.mem]/6 :

A complete-class context of a class is a

(6.1) function body, (6.2) default argument, (6.3) noexcept-specifier ([except.spec]), (6.4) contract condition, or (6.5) default member initializer

within the member-specification of the class. [ Note: A complete-class context of a nested class is also a complete-class context of any enclosing class, if the nested class is defined within the member-specification of the enclosing class. — end note ]

This paragraph was introduced in the draft with pull-request #2231 .

As far as I can understand, the following code should compile, according to the Note above. But it doesn't . I'm assuming that the GCC compiler is still not up to date with the most recent draft. Am I correct, or is it the case that my understanding about this note is incorrect?

struct A {
    int i = 1;
    struct B { 
        int j = 2;
        int f() {
            return i + j;
        }
    };
};

Which fails with:

source>: In member function 'int A::B::f()':
<source>:6:20: error: invalid use of non-static data member 'A::i'
    6 |             return i + j;
      |                    ^
<source>:2:9: note: declared here
    2 |     int i = 1;
      |         ^

I think the confusion stems here from what the point of complete-class context is and how is it intended to be used.

Importantly, name lookup will find i there. So I can write this:

struct A {
    struct B { 
        int j = 2;
        int f() {
            using T = decltype(i); // ok, even though 'i' declared later lexically
            return T{} + j;        // ok
        }
    };
    int i = 1;
};

As well as:

struct A {
    struct B { 
        int j = 2;
        int f() {
            return i + j; // ok, even though 'i' declared later lexically
        }
    };
    static const int i = 1;
};

Indeed, this was ok all the way back in C++11.

But i is still a non-static member, so you can only access it from the context of an object of type A . Within the body of a member function of B , we don't implicitly have an A object. So such a free use of i is still ill-formed.


That said, this:

I'm assuming that the GCC compiler is still not up to date with the most recent draft.

Is certainly true, and will remain true for quite some time.

Then what exactly is that note saying?

Names declared within the class A are in scope within the complete-class context even if before the point of declaration of the name.

The note means that the complete-class context of the enclosing class (noting the pre-condition) extends to the complete-class context of the nested class.

Therefore following is well-formed:

struct A {
    struct B{
        void foo() {
            // names are in scope despite being before point of declaration
            I i;
            var;
        }
    };

     using I = int;
     static int var;
};

You cannot access a non-static data member in a (non-static) member function of another class just like you cannot access non-static members in a static member function of the same class. Complete-class context does not change that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM