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

Name resolution when a structure declaration is hidden by a variable

提问人:Vlad from Moscow 提问时间:10/13/2020 更新时间:10/14/2020 访问量:133

问:

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

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

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

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

不应找到依赖的名称。T::B

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

x == 10

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

那么这是编译器 gcc 8.3 的 bug 吗?

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

typename struct T::B b;

但是,两个编译器都认为该结构不正确。

确实不正确吗?

C++ 模板 C++17 依赖项名称 隐藏

评论

1赞 StoryTeller - Unslander Monica 10/13/2020
这是不正确的。详细类型说明符的正确用法是 - no 。struct T::B b;typename
0赞 Vlad from Moscow 10/13/2020
@StoryTeller-UnslanderMonica 但根据 C++ 17 标准,“2 假定模板声明或定义中使用的名称依赖于模板参数,除非适用的名称查找找到类型名称或名称由关键字 typename 限定,否则不命名类型。也就是说,关键字 typename 是必需的。
0赞 StoryTeller - Unslander Monica 10/13/2020
此外,根据 C++17 标准,“隐式假定用作类或 decltype 或详细类型说明符中名称的限定名称来命名类型,而不使用 typename 关键字。在立即包含依赖于模板参数的嵌套名称说明符的嵌套名称说明符中,隐式假定标识符或 simple-template-id 来命名类型,而不使用 typename 关键字。[ 注意:这些构造的语法不允许使用 typename 关键字。"
0赞 StoryTeller - Unslander Monica 10/13/2020
因此,不仅不是必需的,而且是不允许的 timsong-cpp.github.io/cppwp/n4659/temp.res#5
0赞 Vlad from Moscow 10/13/2020
@StoryTeller-UnslanderMonica 一个很好的参考。我还没有读过这一段。

答:

0赞 0x00001F 10/13/2020 #1

从我的角度来看:在 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();

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

2赞 xmh0511 10/14/2020 #2

这应该是编译器 gcc 8.3 的错误。因为标准规则应解析为变量而不是 ,所以这些规则列在以下列举:typename T::Bstruct B

类名或枚举名称可以通过在同一作用域中声明的变量、数据成员、函数或枚举器的名称来隐藏。如果类或枚举名称与变量、数据成员、函数或枚举器在同一作用域中以相同的名称声明(以任意顺序),则类或枚举名称将隐藏在变量、数据成员、函数或枚举器名称可见的任何位置。

上面的规则说,声明的名称是隐藏的struct Bint B = 20;

当 qualified-id 旨在引用不是当前实例化 ([temp.dep.type]) 成员的类型,并且其嵌套名称说明符引用依赖类型时,应以关键字 typename 为前缀,形成 typename-specifier。如果 typename-specifier 中的 qualified-id 不表示类型或类模板,则程序格式不正确。

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

上面的规则说关键字不影响结果,也就是说关键字不要求名称查找过程只查找类型。typenamequalified name lookuptypename

因此,在 的作用域中,和的声明都被找到,然后变量隐藏 。因此,根据规则,如果 typename-specifier 中的 qualified-id 不表示类型或类模板,则程序格式不正确,则程序应该格式不正确。因此,GCC 8.3 是错误的。Aint B = 20;struct B class name

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