6

Có thể xác định struct (a) không có hàm tạo do người dùng xác định và (b) mà không tạo được hàm tạo mặc định. Ví dụ, Foo ở dưới đây:Liệu nó có vi phạm tiêu chuẩn cho một cấu trúc không cấu hình mặc định để thiếu một hàm tạo do người dùng định nghĩa hay không?

struct Baz 
{ 
    Baz(int) {} 
}; 

struct Foo 
{ 
    int bar; 
    Baz baz; 
}; 

Bạn vẫn có thể tạo ra các trường hợp Foo sử dụng khởi tạo tổng hợp:

Foo foo = { 0, Baz(0) }; 

biên dịch bình thường của tôi (VS2012) miễn cưỡng sẽ chấp nhận điều này, nhưng nó làm tăng 2 cảnh báo:

cảnh báo C4510: 'Foo': hàm tạo mặc định không thể tạo được.

cảnh báo C4610: struct 'Foo' không bao giờ có thể được khởi tạo - sử dụng định nghĩa constructor cần

Tất nhiên, tôi vừa chứng minh cảnh báo # 2 sai - bạn vẫn có thể nhanh chóng nó sử dụng tổng hợp khởi tạo. Các trình biên dịch trực tuyến tôi đã thử là đủ hạnh phúc để chấp nhận ở trên, vì vậy tôi đoán VS2012 chỉ là quá tích cực với cảnh báo này. Nhưng tôi muốn chắc chắn - mã này có ổn không, hoặc nó có vi phạm kỹ thuật một số phần tối nghĩa của tiêu chuẩn không?

+3

Đó chắc chắn là một tập hợp hoàn hảo, có thể được khởi tạo như bạn mô tả, theo C++ 11. Hoặc là có điều gì đó mơ hồ trong các phương ngữ cũ (mà tôi nghi ngờ, nhưng không thể xác nhận, thậm chí ít hơn một nhà sử học ngôn ngữ hơn là một luật sư ngôn ngữ), hoặc trình biên dịch quá nặng với các cảnh báo của nó. –

+0

Chỉ để thoát khỏi cảnh báo, bạn đã thử xóa các constructor mặc định để trình biên dịch không cố gắng không thể? –

+0

Đó không phải là một cấu trúc ít xây dựng. Nó có một hàm khởi tạo sao chép ngầm. –

Trả lời

2

Các tiêu chuẩn cho phép một cách rõ ràng những trường hợp như Foo trong [12.1p4]:

[...] Nếu không có nhà xây dựng sử dụng kê khai lớp X, một constructor không có tham số được ngầm khai báo là mặc định [...] Một mặc định constructor mặc định cho lớp X được định nghĩa là bị xóa nếu:

[...]

  • bất kỳ khả năng xây dựng ed subobject, ngoại trừ thành viên dữ liệu không tĩnh với bộ khởi tạo dấu ngoặc đơn hoặc bằng, có loại M (hoặc mảng ) và M không có hàm tạo mặc định hoặc quá tải độ phân giải (13.3) kết quả constructor mặc định M trong một sự mơ hồ hoặc trong một chức năng đó bị xóa hoặc không thể tiếp cận từ vỡ constructor mặc định

[...]

Baz không có constructor mặc định, vì vậy phần nhấn mạnh ở trên áp dụng (nhấn mạnh m ine)

Không có gì 'không xác định' hoặc 'không đúng định dạng' về các trường hợp như vậy. Hàm khởi tạo mặc định được khai báo ngầm định được định nghĩa là đã xóa, đó là tất cả.Bạn có thể làm điều tương tự một cách rõ ràng, và nó vẫn sẽ là hợp lệ.

Định nghĩa cho tập hợp nằm trong [8.5.1p1]. Đối với C++ 14, đó là:

Một tổng hợp là một mảng hoặc một lớp học (khoản 9) mà không dùng cung cấp constructors (12.1), không có cá nhân hay bảo vệ không tĩnh thành viên dữ liệu (khoản 11), không có lớp cơ sở (Điều 10) và không có chức năng ảo (10.3).

Phần 'không do người dùng cung cấp' cho phép bạn sử dụng = delete trên tất cả các nhà thầu có thể được khai báo hoàn toàn (khiến người dùng khai báo, nhưng không do người dùng cung cấp) và lớp học vẫn là tổng hợp, cho phép bạn sử dụng tổng hợp khởi tạo trên đó.

Đối với cảnh báo C4610, tôi đã gặp cảnh báo trước bản thân mình và reported it. Như bạn có thể thấy, nó đã được sửa trong phiên bản VC++ sắp tới.

Nó có thể là đáng nói đến là ví dụ tôi sử dụng trong báo cáo lỗi được lấy trực tiếp từ các tiêu chuẩn, mà nó coi là tốt được hình thành ([12.2p5.4]:

struct S { int mi; const std::pair<int,int>& mp; }; 
S a { 1, {2,3} }; 

này tương tự trong trường hợp của bạn, nhưng ở đây, hàm tạo mặc định được khai báo ngầm định được định nghĩa là đã bị xóa vì lớp có một thành phần không tĩnh của kiểu tham chiếu không có bộ khởi tạo.

Cấp, nó chỉ là một ví dụ. chỉ ra rằng không có gì sai với những trường hợp này.

+0

Tôi muốn nói rằng giải quyết nó (tôi cũng nói nó xứng đáng được nhiều phiếu hơn). – dlf

-1

Đó thực sự không phải là khởi tạo tổng hợp, đồng bộ, chỉ mới được hỗ trợ bởi VS. Cảnh báo này chỉ đơn giản là họ không cập nhật chính xác nó để phản ánh rằng loại đó bây giờ có thể được khởi tạo đồng bộ.

Tổng hợp có thể không có người xây dựng không được định nghĩa do người dùng không xóa, và các quy tắc cho UDT tổng hợp là mỗi thành viên cũng phải là một tổng hợp. Do đó, Baz không phải là một tổng hợp và như là một kết quả trực tiếp, không thể Foo được.

+5

Eh? 'Foo' là một tổng hợp (dcl.init.aggr/1), và khi một tổng hợp được khởi tạo bởi một danh sách khởi tạo, nó được gọi là khởi tạo tổng hợp (dcl.init.list/3). Không có yêu cầu rằng các thành viên của một tập hợp là các tập hợp khác. –

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