Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is clang or gcc correct about this inner class member access?

Tags:

The following code compiles and works on clang, but fails with "error: invalid use of non-static data member ‘Outer::a’" on gcc:

#include <functional>
#include <vector>
#include <assert.h>
#include <iostream>
#include <memory>

class Outer
{
public:
    bool a = false;

    virtual void f() = 0;

    template <typename T>
    class Inner : public T
    {
    public:
        virtual void f() override
        {
            a = true; // Note: accessed through inheritance, not through outer scope
        }
    };
};

struct Foo : Outer { };

int main()
{
    Outer::Inner<Foo> f;
    f.f();
}

Adding "this->a" to the inner class makes it work on both compilers, but I'm wondering what's the correct behavior and what the standards says about this.

Interestingly the above code works with as part of a larger code base in VS2017 at work, but when I try it at home with VS2017 in isolation, it fails with the same error as GCC.

You can try compiling it here:

  • clang: https://rextester.com/SKAUEY50097
  • gcc: https://rextester.com/FLGL37556
like image 373
monoceres Avatar asked Jan 09 '19 20:01

monoceres


1 Answers

This code is ill-formed no diagnostic required. So Gcc is right and friendly. And the absence of diagnostic for Clang and MSVC is just a compiler quality issue.

The rule of the standard involved is [temp.res]/8:

The validity of a template may be checked prior to any instantiation. [ Note: Knowing which names are type names allows the syntax of every template to be checked in this way. — end note  ] The program is ill-formed, no diagnostic required, if:

  • [..]

  • a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter, or [...]

In f body, the unqualified id-expression a does not depend on any template parameter, so this id-expression should be resolved at the point of definition of the template without the knowledge of any template argument. And at this point, this expression is ill-formed.


Note: a non qualified id-expression, (out of a class member access) expression is supposed to be a member only if it names a member of that class or of a non-dependent base [temp.dep.type]/5:

A name is a member of the current instantiation if it is:

  • An unqualified name that, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof.
like image 87
Oliv Avatar answered Nov 12 '22 15:11

Oliv