提问人:Adrian McCarthy 提问时间:2/13/2010 最后编辑:underscore_dAdrian McCarthy 更新时间:11/28/2022 访问量:78120
为什么 C++ 不允许匿名结构?
Why does C++ disallow anonymous structs?
问:
一些 C++ 编译器允许匿名联合和结构作为标准 C++ 的扩展。这是一些句法糖,偶尔很有帮助。
阻止它成为标准一部分的理由是什么?是否存在技术障碍?一个哲学的?还是没有足够的必要来证明它的合理性?
以下是我所说的示例:
struct vector3 {
union {
struct {
float x;
float y;
float z;
};
float v[3];
};
};
我的编译器会接受这一点,但它警告说“无名结构/联合”是C++的非标准扩展。
答:
不知道你的意思。C++规范第9.5节,第2条:
形式的联合
union { member-specification } ;
被称为匿名工会;它定义了一个未命名类型的未命名对象。
你也可以做这样的事情:
void foo()
{
typedef
struct { // unnamed, is that what you mean by anonymous?
int a;
char b;
} MyStructType; // this is more of a "C" style, but valid C++ nonetheless
struct { // an anonymous struct, not even typedef'd
double x;
double y;
} point = { 1.0, 3.4 };
}
并不总是很有用......尽管有时在令人讨厌的宏定义中很有用。
评论
工会可以是匿名的;见《标准》第9.5条第2款。
你认为匿名结构或类的目的是什么?在推测为什么某些东西不在标准中之前,我想先了解一下为什么它应该如此,而且我认为匿名结构没有用处。
您的代码
union {
struct {
float x;
float y;
float z;
};
float v[3];
};
就像
union Foo {
int;
float v[3];
};
这肯定是无效的(在 C99 及之前)。
原因可能是为了简化解析(在 C 中),因为在这种情况下,您只需要检查结构/联合体是否只有“声明符语句”,例如
Type field;
也就是说,gcc 和“其他编译器”支持未命名字段作为扩展。
编辑:C11 (§6.7.2.1/13) 现在正式支持匿名结构。
评论
union { ... }
struct { ... }
union { ... };
根据编辑、评论和这篇 MSDN 文章:匿名结构,我冒昧地猜测一下 - 它与封装的概念不太吻合。我不希望类的成员除了仅仅添加一个成员之外弄乱我的类命名空间。此外,对匿名结构的更改可能会在未经许可的情况下影响我的类。
评论
正如其他人所指出的,在标准C++中允许匿名联合,但匿名结构则不允许。
这样做的原因是 C 支持匿名联合,但不支持匿名结构*,因此 C++ 支持前者以实现兼容性,但不支持后者,因为不需要兼容性。
此外,C++中的匿名结构没有多大用处。您演示的用法是,拥有一个包含三个浮点数的结构,这些浮点数可以由 、 或 、 和 引用,我相信会导致 C++ 中未定义的行为。C++ 不允许你写信给一个联合的一个成员,比如 ,然后从另一个成员那里读,比如 。尽管这样做的代码并不少见,但实际上并没有很好地定义。.v[i]
.x
.y
.z
.v[1]
.y
C++ 针对用户定义类型的工具提供了替代解决方案。例如:
struct vector3 {
float v[3];
float &operator[] (int i) { return v[i]; }
float &x() { return v[0]; }
float &y() { return v[1]; }
float &z() { return v[2]; }
};
* C11 显然添加了匿名结构,因此将来的 C++ 修订版可能会添加它们。
评论
我会说,你可以通过使用vector3
union
union vector3 {
struct { float x, y, z; } ;
float v[3] ;
} ;
当然,匿名结构是 MSVC 的扩展。但是 ISO C11 现在允许它,gcc 允许它,Apple 的 llvm 编译器也是如此。
为什么在 C11 而不是 C++11?我不确定,但实际上大多数(gcc++,MSVC++和Apple的C++编译器)C++编译器都支持它们。
评论
编辑:我提出了一个非答案,因为我没有意识到“匿名结构”和“未命名结构”之间的区别。我不会删除这个答案,而是把它留下来,但我在这里的回答是不正确的。
原文如下:
我在这里的任何答案中都没有提到它,我想因为它们大多是在“现代C++”时代之前写的,但是由于我通过谷歌搜索“C++匿名结构”找到了我的方式,我将把这个答案放在这里:
我能够做到以下几点:
struct /* no typename */
{
int i=2;
} g_some_object{};
int main()
{
return g_some_object.i;
}
我注意到这种行为实际上在 cpppreference 上的 C++20 协程的一些示例中被利用,特别是用于演示任务等待者。
如果在过去任何时候这种行为是不允许的,那么现在情况就不再如此了——我们现在绝对可以这样做。
评论
struct
struct
评论
struct { int i; } a; a.i = 0;
struct { int i; }; i = 0;