为什么 C + + 不允许匿名结构?

一些 C + + 编译器允许匿名联合和结构作为标准 C + + 的扩展。这是一点句法糖,有时非常有帮助。

是什么原理阻止了这成为标准的一部分?有技术障碍吗?哲学上的?或者只是没有足够的必要去证明它?

下面是我所说的一个例子:

struct vector3 {
union {
struct {
float x;
float y;
float z;
};
float v[3];
};
};

我的编译器会接受这个,但它会警告 “无名 struct/union”是 C + + 的非标准扩展

71905 次浏览

Not sure what you mean. Section 9.5 of the C++ spec, clause 2:

A union of the form

union { member-specification } ;

is called an anonymous union; it defines an unnamed object of unnamed type.

You can do things like this too:

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 };
}

Not always very useful... although sometimes useful in nasty macro definitions.

Unions can be anonymous; see the Standard, 9.5 paragraph 2.

What purpose do you see an anonymous struct or class as fulfilling? Before speculating why something isn't in the Standard, I'd like to have some idea why it should be, and I don't see a use for an anonymous struct.

Your code

union {
struct {
float x;
float y;
float z;
};
float v[3];
};

is like

union Foo {
int;
float v[3];
};

which is surely invalid (in C99 and before).

The reason is probably to simplify parsing (in C), because in that case you only need to check that the struct/union body has only "declarator statements" like

Type field;

That said, gcc and "other compilers" supports unnamed fields as an extension.

Edit: Anonymous structs are now officially supported in C11 (§6.7.2.1/13).

Based on the edit, the comments, and this MSDN article: Anonymous Structures, I'll hazard a guess - it fits poorly with the concept of encapsulation. I wouldn't expect a member of a class to mess with my class namespace beyond merely adding one member. Furthermore, changes to the anonymous structure can affect my class without permission.

As others have pointed out anonymous unions are permitted in standard C++, but anonymous structs are not.

The reason for this is that C supports anonymous unions but not anonymous structs*, so C++ supports the former for compatibility but not the latter because it's not needed for compatibility.

Furthermore, there's not much use to anonymous structs in C++. The use you demonstrate, to have a struct containing three floats which can be referred to either by .v[i], or .x, .y, and .z, I believe results in undefined behavior in C++. C++ does not allow you to write to one member of a union, say .v[1], and then read from another member, say .y. Although code that does this is not uncommon it is not actually well defined.

C++'s facilities for user-defined types provide alternative solutions. For example:

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 apparently adds anonymous structs, so a future revision to C++ may add them.

I'll say, you can clean up your vector3 declaration by just using a union

union vector3 {
struct { float x, y, z; } ;
float v[3] ;
} ;

Sure, anonymous structures was an MSVC extension. But ISO C11 permits it now, and gcc allows it, and so does Apple's llvm compiler.

Why in C11 and not C++11? I'm not sure, but practically speaking most (gcc++, MSVC++ and Apple's C++ compiler) C++ compilers support them.

Edit: I put up a non-answer since I didn't realize the difference between an "anonymous struct" and an "unnamed struct". Rather than delete this answer, I will just leave it up, but my response here is not correct.

Original response follows:


I don't see it mentioned in any of the answers here, I guess since they're mostly written from before the "modern C++" era, but since I found my way here via a google search on "C++ anonymous struct", I'll just put this answer down here:

I'm able to do the following:

struct /* no typename */
{
int i=2;
} g_some_object{};


int main()
{
return g_some_object.i;
}

I noticed this behavior is actually leveraged in some of the examples for C++20 coroutines on cppreference, particularly for demonstrating a task awaiter.

If at any point in the past this behavior was not allowed, then that's no longer the case--we can definitely do this now.

https://godbolt.org/z/nT1E7e8To

This asserts and proves that this is defined behavior in this case. You just have to check if the compilers you are going to use support anonymous structs. This is a must have feature. It would be a great waste not to use it.

#include <cstddef>


struct vec3
{
union {
float values[3]{};
struct {
float x, y, z;
};
};


constexpr vec3(float x, float y, float z)
: values { x, y, z }
{}
};


static_assert(offsetof(vec3, values[0]) == offsetof(vec3, x), "!-_-!");
static_assert(offsetof(vec3, values[1]) == offsetof(vec3, y), "!-_-!");
static_assert(offsetof(vec3, values[2]) == offsetof(vec3, z), "!-_-!");