提问人:Vlad from Moscow 提问时间:10/13/2020 更新时间:10/14/2020 访问量:133
结构声明被变量隐藏时的名称解析
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();
}
可以看出,结构中成员的声明被具有 类型的数据成员的声明所隐藏。struct B
A
B
int
所以在模板结构声明的函数定义中
typename /*struct*/ T::B b;
不应找到依赖的名称。T::B
但是,编译器成功编译程序,程序输出gcc 8.3
x == 10
另一方面,编译器 Visual C++ 2019 不会编译程序并发出语法错误。
那么这是编译器 gcc 8.3 的 bug 吗?
第二个问题是,如果允许这种带有详细类型说明符的构造(带有未注释的关键字结构),那将是很自然的。
typename struct T::B b;
但是,两个编译器都认为该结构不正确。
确实不正确吗?
答:
从我的角度来看:在 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;
}
};
在主调用 f( ) 中,通常如下所示:
C<A> j;
// call
j.f();
我希望所有这些都值得:)
这应该是编译器 gcc 8.3 的错误。因为标准规则应解析为变量而不是 ,所以这些规则列在以下列举:typename T::B
struct B
类名或枚举名称可以通过在同一作用域中声明的变量、数据成员、函数或枚举器的名称来隐藏。如果类或枚举名称与变量、数据成员、函数或枚举器在同一作用域中以相同的名称声明(以任意顺序),则类或枚举名称将隐藏在变量、数据成员、函数或枚举器名称可见的任何位置。
上面的规则说,声明的名称是隐藏的struct B
int B = 20;
当 qualified-id 旨在引用不是当前实例化 ([temp.dep.type]) 成员的类型,并且其嵌套名称说明符引用依赖类型时,应以关键字 typename 为前缀,形成 typename-specifier。如果 typename-specifier 中的 qualified-id 不表示类型或类模板,则程序格式不正确。
通常的限定名称查找用于查找 qualified-id,即使存在 typename。
上面的规则说关键字不影响结果,也就是说关键字不要求名称查找过程只查找类型。typename
qualified name lookup
typename
因此,在 的作用域中,和的声明都被找到,然后变量隐藏 。因此,根据规则,如果 typename-specifier 中的 qualified-id 不表示类型或类模板,则程序格式不正确,则程序应该格式不正确。因此,GCC 8.3 是错误的。A
int B = 20;
struct B
class name
此外,不仅,而且更高版本都是错误的。GCC 8.3
下一个:为什么这不是一个独立的名字?
评论
struct T::B b;
typename