2

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

#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为 的数据成员的声明所隐藏。Bint

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

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

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

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

x == 10

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

那么它是编译器gcc 8.3的错误吗?

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

typename struct T::B b;

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

确实不正确吗?

4

2 回答 2

2

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

类名或枚举名可以被同一作用域中声明的变量、数据成员、函数或枚举器的名称隐藏。如果一个类或枚举名称和一个变量、数据成员、函数或枚举器在同一范围内(以任何顺序)以相同名称声明,则无论变量、数据成员、函数或枚举器名称可见。

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

当qualified-id 旨在引用不是当前实例化成员的类型([temp.dep.type])并且其nested-name-specifier 引用依赖类型时,应以关键字为前缀typename,形成一个 typename-specifier。如果 typename-specifier 中的qualified-id 不表示类型或类模板,则程序格式错误。

即使在 typename 存在的情况下,通常的限定名称查找也用于查找限定 ID。

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

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

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

于 2020-10-14T02:27:58.800 回答
0

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

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

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

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

于 2020-10-13T13:41:47.067 回答