2010-02-12 39 views
66

Một số trình biên dịch C++ cho phép các công đoàn và cấu trúc ẩn danh như một phần mở rộng cho tiêu chuẩn C++. Đó là một chút đường cú pháp đôi khi rất hữu ích.Tại sao C++ không cho phép cấu trúc ẩn danh?

Lý do ngăn cản điều này là một phần của tiêu chuẩn là gì? Có một rào cản kỹ thuật không? Một triết lý? Hay không đủ để cần biện minh cho nó?

Dưới đây là một ví dụ về những gì tôi đang nói về:

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

trình biên dịch của tôi sẽ chấp nhận điều này, nhưng nó cảnh báo rằng "nameless struct/union" is a non-standard extension to C++.

+3

Rõ ràng có một số nhầm lẫn về ý của bạn. Bạn có thể vui lòng cung cấp một ví dụ về mã chỉ biên dịch do mở rộng trình biên dịch không? –

+54

Lưu ý rằng có hai khái niệm, có vẻ giống nhau, nhưng rất khác nhau: * cấu trúc chưa đặt tên * và * cấu trúc ẩn danh *. Đầu tiên là cái này, mà C++ hỗ trợ: 'struct {int i; } a; a.i = 0; '(loại không có tên). Thứ hai là cái này, mà C++ không * không * hỗ trợ: 'struct {int i; }; i = 0; '(loại không có tên, và nó thoát ra ngoài phạm vi xung quanh). C++, tuy nhiên, * có * hỗ trợ cả hai unionsed và nặc danh * unions *. –

+0

Điều này trông giống như thư viện vector VMMLib khá thú vị. Tôi tin rằng vấn đề là công đoàn có cấu trúc chưa đặt tên, nhưng tôi không chắc chắn. – greyfade

Trả lời

30

Vì những người khác đã chỉ ra các công đoàn ẩn danh được phép trong tiêu chuẩn C++, nhưng cấu trúc ẩn danh thì không.

Lý do cho điều này là C hỗ trợ các tổ chức ẩn danh nhưng không hỗ trợ cấu trúc ẩn danh *, vì vậy C++ hỗ trợ cấu hình tương thích trước đây nhưng không hỗ trợ tính tương thích.

Hơn nữa, không có nhiều sử dụng cho cấu trúc ẩn danh trong C++. Cách bạn sử dụng, để có cấu trúc chứa ba phao có thể được tham chiếu bằng .v[i] hoặc .x, .y.z, tôi tin rằng kết quả là hành vi không xác định trong C++. C++ không cho phép bạn viết thư cho một thành viên của một công đoàn, nói .v[1], và sau đó đọc từ một thành viên khác, nói .y. Mặc dù mã thực hiện điều này không phải là không phổ biến nhưng nó không thực sự được xác định rõ.

Cơ sở của C++ dành cho các loại do người dùng xác định cung cấp giải pháp thay thế. Ví dụ:

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 dường như thêm cấu trúc mang tính chất do đó, một phiên bản tương lai để C++ có thể thêm chúng.

+2

+1: Ví dụ của tôi dựa trên hành vi không xác định trong C++ - một cái gì đó tôi đã không nhận thức được trở lại khi tôi đã viết câu hỏi. –

+0

"C++ không cho phép bạn ghi vào một thành viên của công đoàn [...] và sau đó đọc từ thành viên khác" - ** trừ khi ** thành viên nói là đối tượng bố cục tiêu chuẩn và chia sẻ một chuỗi _common ban đầu_ của các thành viên của riêng bạn và bạn đang viết/đọc các thành viên _their_ trong chuỗi ban đầu chung được cho biết. Đó là _is_ được phép (tức là đã xác định). –

+1

@underscore_d: Có, nếu các loại là bố cục chuẩn với chuỗi ban đầu chung. Tuy nhiên, một cấu trúc không bao giờ có thể bí danh với một mảng * theo cách này, bởi vì các quy tắc "chuỗi ban đầu chung" của C++ nói rằng một chuỗi ban đầu chung chỉ có thể nằm giữa * struct *. Mảng không được đề cập, vì vậy chúng không thể bí danh như thế này. –

7

Không chắc chắn ý của bạn là gì. Phần 9,5 của ++ đặc tả C, khoản 2:

Một đoàn của mẫu

union { member-specification } ; 

được gọi là một đoàn vô danh; nó định nghĩa một đối tượng chưa được đặt tên của kiểu chưa đặt tên.

Bạn có thể làm những việc như quá này:

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

Không luôn rất hữu ích ... mặc dù đôi khi hữu ích trong việc định nghĩa vĩ mô khó chịu.

+8

-1 vì nó nói rằng nó định nghĩa một cấu trúc ẩn danh. Xem nhận xét ở trên về câu hỏi - bạn đang xác định cấu trúc chưa đặt tên, không phải là cấu trúc ẩn danh. –

1

Công đoàn có thể ẩn danh; xem Tiêu chuẩn, 9,5 đoạn 2.

Bạn thấy cấu trúc hoặc lớp ẩn danh nào là hoàn thành? Trước khi suy đoán tại sao một cái gì đó không có trong tiêu chuẩn, tôi muốn có một số ý tưởng tại sao nó nên được, và tôi không thấy một sử dụng cho một cấu trúc vô danh.

1

Mã của bạn

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

là như

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

mà chắc chắn là không hợp lệ (trong C99 và trước đó).

Lý do là lẽ để đơn giản hóa phân tích (trong C), bởi vì trong trường hợp đó, bạn chỉ cần kiểm tra xem cơ thể struct/đoàn chỉ có "báo cáo declarator" như

Type field; 

Điều đó nói rằng, gcc and "other compilers" hỗ trợ các trường chưa đặt tên dưới dạng tiện ích mở rộng.

Chỉnh sửa: Cấu trúc ẩn danh hiện được hỗ trợ chính thức trong C11 (§6.7.2.1/13).

+5

Từ góc độ phân tích cú pháp, tôi không nghĩ rằng 'union {...}' khác với 'struct {...}'. Cái cũ là hợp lệ, nhưng cái thứ hai thì không. –

+2

Với cách C++ vô lý khó phân tích nói chung, tôi nghi ngờ tiêu chuẩn cam kết các cấu trúc không được phép và các công đoàn chỉ để đơn giản hóa việc phân tích cú pháp. –

+0

@Adrian: Tôi đã nói C, chứ không phải C++. C++ sử dụng cú pháp C và mở rộng nó. Có lẽ những người sáng tạo của C++ không thấy cần phải cho phép các thành viên cấu trúc/công đoàn chưa đặt tên để họ không gây rối với phần cú pháp đó. – kennytm

1

Dựa trên chỉnh sửa, nhận xét và bài viết MSDN này: Anonymous Structures, tôi sẽ gây nguy hiểm cho dự đoán - nó phù hợp kém với khái niệm đóng gói. Tôi sẽ không mong đợi một thành viên của một lớp học lộn xộn với không gian tên lớp của tôi ngoài việc chỉ thêm một thành viên. Hơn nữa, thay đổi cấu trúc ẩn danh có thể ảnh hưởng đến lớp học của tôi mà không được phép.

+0

Do cách thức cấu trúc/liên kết ẩn danh được tạo ra (cú pháp nội tuyến đặc biệt không thể ẩn trừ macro) bạn không thể ngạc nhiên khi một số thành viên bạn đang sử dụng là một thành viên ẩn danh. Vì vậy, tôi không nghĩ rằng lý do này làm cho bất kỳ ý nghĩa. Lý do thực sự là các liên kết ẩn danh _are_ được hỗ trợ trong C++, chỉ cho tính tương thích của C. C không hỗ trợ cấu trúc ẩn danh (cho đến C11) và vì vậy C++ cũng không. – bames53

14

tôi sẽ nói, bạn có thể dọn dẹp khai vector3 của bạn bằng cách chỉ sử dụng một union

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

Chắc chắn, anonymous structures was an MSVC extension. Nhưng ISO C11 cho phép nó ngay bây giờ, và gcc allows it, và do đó, trình biên dịch llvm của Apple.

Tại sao trong C11 chứ không phải C++ 11? Tôi không chắc chắn, nhưng thực tế nói nhiều nhất (gcC++, MSVC++ và trình biên dịch C++ của Apple) trình biên dịch C++ hỗ trợ chúng.

+0

+1 để biết thông tin cập nhật. Lý do tôi có cấu trúc bên ngoài là vì "mã thực" cũng có các phương thức. –

+0

Những điều duy nhất bạn không thể làm với một công đoàn là [có thành viên dữ liệu tĩnh, hoặc sử dụng thừa kế] (http://msdn.microsoft.com/en-us/library/5dxy4b7b.aspx). – bobobobo

+0

Cảm ơn. Tôi không bao giờ mới một công đoàn có thể được sử dụng như một cấu trúc hoặc lớp học. –

Các vấn đề liên quan