C++ 我可以使用相同的名称为周围作用域中的类型声明成员类型别名吗?
出于元编程目的,我希望结构包含另一个类型的类型别名:C++ 我可以使用相同的名称为周围作用域中的类型声明成员类型别名吗?,c++,g++,c++14,clang++,type-alias,C++,G++,C++14,Clang++,Type Alias,出于元编程目的,我希望结构包含另一个类型的类型别名: struct Foo {}; struct WithNestedTypeAlias { using Foo = Foo; }; 然后我可以用NestedTypeAlias::Foo在模板中执行类似的,等等 据我所知,此类型别名是有效的,因为它不会更改Foo类型的含义。Clang很高兴地编写了这个 然而,GCC抱怨: test-shadow-alias.cpp:4:20: error: declaration of ‘using F
struct Foo {};
struct WithNestedTypeAlias {
using Foo = Foo;
};
然后我可以用NestedTypeAlias::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进行测试,但是
- 我看了一下,其中变量的名称可能引用外部范围中的变量或类成员。相反,我这里的问题是关于类型别名的。没有歧义,因为
Foo
总是指类范围内的::Foo
。我不明白那里的答案如何适用于我的问题
- 这可能是因为误解了别名的实际类型
GCC正在执行的规则在[basic.scope.class]中:
2) 类S中使用的名称N在其上下文中以及在完成的S范围内重新评估时应引用相同的声明。违反此规则无需诊断
该标准称,违反此要求不需要诊断,因此GCC和Clang可能都符合要求,因为(如果GCC是正确的)代码无效,但编译器不需要对其进行诊断
此规则的目的是使类中使用的名称始终具有相同的含义,并且对成员重新排序不会改变它们的解释方式,例如
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是正确的。使用Foo=:Foo将语句更改为代码>修复了它,但我无法解释原因代码>也修复了它。请注意,等效的typedef struct Foo Foo
是惯用的C代码。嗯,这个规则是有意义的。但这似乎意味着我不应该使用弗朗索瓦·安德烈在上面的评论中提到的使用Foo=::Foo
技巧?虽然这一点目前正在发挥作用,但它仍然是Foo
的新声明,因此违反了您引用的规则,对吗?因此,这将留给我唯一的解决方案struct AnotherFoo{};嵌套结构{using Foo=AnotherFoo;};使用Foo=另一个Foo
用于可移植地执行嵌套的Foo
声明。@amon:原始代码中的问题是,右侧的Foo
更改了含义,因为它是不合格的。在使用
声明之前,它意味着全局Foo,之后它意味着别名。如果它是合格的,那么这就不再是一个问题。@amon还注意到,这将回答您关于Foo
,::Foo
和所有内容的问题。@amon规则不是说Foo
不能更改其含义,而是在其含义更改之前不得使用它。因此使用Foo=::Foo
是可以的,因为非限定的Foo
在其含义更改之前不会被使用。类似地,如果我们简单地用1
@Oktalist替换sizeof(N)
,答案中的示例就可以了,我现在明白了。感谢您的帮助:)