我可以使用相同的名称为周围范围内的类型声明一个成员类型别名吗?

May I declare a member type alias to a type in a surrounding scope, using the same name?

我想要一个结构包含另一个类型的类型别名以用于元编程目的:

struct Foo {};

struct WithNestedTypeAlias {
    using Foo = Foo;
};

然后我可以在模板中做 WithNestedTypeAlias::Foo 之类的事情

据我了解,此类型别名是有效的,因为它不会更改 Foo 类型的含义。 Clang 愉快地编译了这个。

但是,GCC 抱怨:

test-shadow-alias.cpp:4:20: error: declaration of ‘using Foo = struct Foo’ [-fpermissive]
     using Foo = Foo;
                    ^
test-shadow-alias.cpp:1:8: error: changes meaning of ‘Foo’ from ‘struct Foo’ [-fpermissive]
 struct Foo {};
        ^

现在我很困惑,因为我明确没有改变 struct FooFoo 的含义。

C++14 的正确行为是什么?我知道我可以通过重命名 struct Foo 来解决这个问题,但我想了解 GCC 的错误在这里是否正确。

备注:

GCC 正在执行的规则在 [basic.scope.class]:

2) A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule.

标准说违反此不需要诊断,因此 GCC 和 Clang 可能都符合标准,因为(如果 GCC 是正确的)代码无效,但编译器不需要诊断它.

此规则的目的是让 class 中使用的名称始终表示相同的意思,并且重新排序成员不会改变它们的解释方式,例如

struct N { };

struct S {
  int array[sizeof(N)];

  struct N { char buf[100]; };
};

在此示例中,名称 N 改变了含义,重新排序成员将改变 S::array 的大小。当定义 S::array 时,N 指的是类型 ::N,但在 S 的完整范围内,它指的是 S::N。这违反了上面引用的规则。

在您的示例中,名称 Foo 的更改危险性要小得多,因为它仍然指代相同的类型,但严格来说,它确实从引用 ::Foo 的声明更改为S::Foo 的声明。该规则是根据声明来表述的,所以我认为 GCC 是正确的。