微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

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

#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 错误吗?

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

typename struct T::B b;

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

这确实不正确吗?

解决方法

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

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

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

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

通常的合格名称查找用于查找合格ID,即使存在typename也是如此。

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

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

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

,

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。