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



让我们考虑下面的演示程序。

#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;

不应该找到依赖名称CCD_ 5。

然而,编译器gcc 8.3成功地编译了程序,并且程序输出

x == 10

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

那么这是编译器gcc8.3的错误吗?

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

typename struct T::B b;

然而,两个编译器都认为这种构造是不正确的。

这真的不正确吗?

这应该是编译器gcc 8.3的一个bug。由于标准规则typename T::B应解析为变量,而不是struct B,因此以下列出了这些规则:

类名称或枚举名称可以由同一作用域中声明的变量、数据成员、函数或枚举器的名称隐藏。如果类或枚举名称与变量、数据成员、函数或枚举器在相同的范围内(以任何顺序(以相同的名称声明,则只要变量、数据会员、函数或列举器名称可见,则该类或枚举器名称就会隐藏。

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

当限定id旨在引用不是当前实例化([temp.dep.type](成员的类型,并且其嵌套的名称说明符引用依赖类型时,应在其前面加上关键字typename,形成typename说明符。如果typename说明符中的限定id不表示类型或类模板,则程序格式错误。

通常的限定名称查找用于查找限定id,即使存在typename。

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

因此,在A的范围内,int B = 20;struct B的声明都被找到,然后变量隐藏class name。因此,根据规则,如果typename说明符中的限定id不表示类型或类模板,则程序格式错误,则程序应该格式错误。因此,GCC 8.3是错误的。

此外,不仅GCC 8.3,而且更高版本都是错误的。

根据我的设想:在f((函数中,您需要声明结构来避免这个问题

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();

我希望所有这些都有价值:(

最新更新