类型别名与类型同名

9
这在C++中是有效的吗?
#include <iostream>


class Test {

    struct Inner {
    };

public:
    using Inner = struct Inner;  // Alias with same name as type
};

int main(int argc, const char * argv[]) {
    static_assert(std::is_pod<Test::Inner>::value, "");
    
    return 0;
}

使用Clang编译没有问题,但使用GCC / Visual C++会出现“Inner is private…”错误信息。

2个回答

5

GCC和Visual C++都是正确的。

实际上,您可以使用using来改变成员的访问权限,例如:

using Inner_ = Inner;

使用

static_assert(std::is_pod<Test::Inner_>::value, "");

在函数中。

但是,当类型别名与成员具有相同的名称时,C++要求作用域解析运算符查找成员。 因此,在您的情况下,Test :: Inner指的是实际成员而不是using,因此编译应该失败,因为它是private


请参见https://en.cppreference.com/w/cpp/language/qualified_lookup,特别是

在命名空间N的范围内进行限定查找,首先考虑位于N中的所有声明以及位于N的内联命名空间成员(以及经由运输工具加入其中的所有内联命名空间成员)。 如果该集合中没有声明,则会考虑N中找到的所有使用指令命名的名称空间中的声明以及N的所有传递性内联命名空间成员中的所有声明


1
不确定这个引用是否适用。如果我正确理解了这里using x = y;不是一个using-directive,而是一个using-declaration - HolyBlackCat
@HolyBlackCat:这是一个棘手的问题。我相当确定这是正确的(我记得在某次会议上遇到过这个问题)。我也相当确定程序不仅仅是格式错误。希望语言专家之一能够介入。我将调整问题标签以吸引注意力。 - Bathsheba
1
@HolyBlackCat 这甚至不是一个使用声明(例如 using std::swap;);它是一个别名声明。 - L. F.

1

P1787R6: Declarations and where to find them 已经合并到 C++23 草案中,似乎更倾向于 Clang 的行为:

[basic.lookup]

在某些情况下,只包括某些类型的声明。在任何这样的限制之后,如果找到任何其他声明,则会丢弃任何类或枚举的声明。[注意:因此,在其作用域中的任何其他实体都会隐藏类型(但不是typedef名称或模板)。—注] 但是,如果查找是“仅类型”,则仅考虑类型和其特化为类型的模板的声明;此外,如果找到typedef名称和它所引用的类型的声明,则会丢弃typedef名称的声明而不是类型声明。

所以,struct Inner 的声明被丢弃了,因为找到了别名声明。(可以将Inner放入仅限类型的上下文中——Test::struct Inner——它将引用第二部分的struct Inner声明)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接