我可以使用相同的名称为周围范围内的类型声明一个成员类型别名吗?
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 Foo
的 Foo
的含义。
C++14 的正确行为是什么?我知道我可以通过重命名 struct Foo
来解决这个问题,但我想了解 GCC 的错误在这里是否正确。
备注:
已使用 clang++ 3.8 和 gcc 5.4 进行测试,但 Godbolt suggests this hasn't changed in more recent GCC versions.
我查看了 Interaction between decltype and class member name shadowing an external name,其中 变量的名称 可能指的是外部作用域中的变量或 class 成员。相反,我的问题是关于类型别名。没有歧义,因为 Foo
总是在 class 范围内引用 ::Foo
。我不明白那里的答案如何适用于我的问题。
这可能是由于误解了类型别名的实际含义。
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 是正确的。
我想要一个结构包含另一个类型的类型别名以用于元编程目的:
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 Foo
的 Foo
的含义。
C++14 的正确行为是什么?我知道我可以通过重命名 struct Foo
来解决这个问题,但我想了解 GCC 的错误在这里是否正确。
备注:
已使用 clang++ 3.8 和 gcc 5.4 进行测试,但 Godbolt suggests this hasn't changed in more recent GCC versions.
我查看了 Interaction between decltype and class member name shadowing an external name,其中 变量的名称 可能指的是外部作用域中的变量或 class 成员。相反,我的问题是关于类型别名。没有歧义,因为
Foo
总是在 class 范围内引用::Foo
。我不明白那里的答案如何适用于我的问题。这可能是由于误解了类型别名的实际含义。
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 是正确的。