当结构声明被变量隐藏时的名称解析

Name resolution when a structure declaration is hidden by a variable

让我们考虑以下演示程序。

#include <iostream>

struct A
{
    struct B 
    {
        int b = 10;
    };
    int B = 20;
};

template <class T>
struct C
{
    void f() const
    {
        typename /*struct*/ T::B b;
        int x = b.b;
        std::cout << "x == " << x << '\n';
    }
};

int main()
{
    C<A>().f();
}

正如所见,结构 A 中成员 struct B 的声明被具有类型 int 的数据成员 B 的声明隐藏了。

所以在模板结构声明的函数定义中

typename /*struct*/ T::B b;

应该找不到相关名称 T::B

但是编译器gcc 8.3编译程序成功,程序输出

x == 10

另一方面,编译器Visual C++ 2019不会编译程序并发出语法错误。

所以是不是编译器的bug gcc 8.3?

第二个问题是,如果允许这种带有详细类型说明符的构造(带有未注释的关键字结构),那将是很自然的。

typename struct T::B b;

然而,两个编译器都认为该构造不正确。

是否确实不正确?

从我的角度来看:在 f( ) 函数中你需要声明 struct 来避免这个问题

template <class T> struct C {
        void f() const {
            // just normal struct
            struct T::B structB;
            int x = structB.b;
    
            std::cout << "x == " << x << std::endl;
    }
};

并在 main 中调用 f( ) 通常是这样的:

C<A> j; 
// call
j.f();

我希望所有这些都值得:)

应该是编译器gcc 8.3的bug。因为标准规则typename T::B应该解析为变量而不是struct B,这些规则如下:

A class name or enumeration name can be hidden by the name of a variable, data member, function, or enumerator declared in the same scope. If a class or enumeration name and a variable, data member, function, or enumerator are declared in the same scope (in any order) with the same name, the class or enumeration name is hidden wherever the variable, data member, function, or enumerator name is visible.

上面的规则说 struct B 的名字被声明的名字 int B = 20;

隐藏了

When a qualified-id is intended to refer to a type that is not a member of the current instantiation ([temp.dep.type]) and its nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword typename, forming a typename-specifier. If the qualified-id in a typename-specifier does not denote a type or a class template, the program is ill-formed.

The usual qualified name lookup is used to find the qualified-id even in the presence of typename.

上面的规则说关键字typename不影响qualified name lookup的结果,换句话说,关键字typename不要求名称查找过程只查找类型。

所以,在A的范围内,int B = 20;struct B 的声明都找到了,然后变量隐藏class name。因此,根据规则 如果 typename-specifier 中的 qualified-id 不表示类型或 class 模板,则程序为 ill-formed,程序应该是ill-formed。因此,GCC 8.3 是错误的。

另外,不仅GCC 8.3,高版本也都是错误的