41

Giả sử có một số std::array được khởi tạo. Không sao đâu nếu sử dụng dấu ngoặc kép:Cắt bỏ cú đúp trong std :: khởi tạo mảng

std::array<int, 2> x = {{0, 1}}; 
std::array<int, 2> x{{0, 1}}; 

Nó cũng không quan trọng để sử dụng dấu ngoặc đơn trong khởi tạo tổng hợp cũ tốt, là sự bỏ bớt cú đúp sẽ chăm sóc của niềng răng mất tích:

std::array<int, 2> x = {0, 1}; 

Tuy nhiên, là có ổn không khi sử dụng danh sách khởi tạo với dấu ngoặc đơn? GCC chấp nhận nó, Clang từ chối nó với "không thể bỏ qua niềng răng xung quanh khởi tạo subobject khi sử dụng trực tiếp danh sách khởi tạo".

std::array<int, 2> x{0, 1}; 

Phần duy nhất của tiêu chuẩn nơi cú đúp sự bỏ bớt được nhắc đến là 8.5.1/12, trong đó nói rằng:

Tất cả các loại ngầm chuyển đổi (khoản 4) được xem xét khi khởi tạo các thành viên tổng hợp với một biểu thức gán. Nếu biểu thức gán có thể khởi tạo thành viên, thành viên được khởi tạo. Nếu không, nếu thành viên tự nó là một phân nhóm, thì sự bỏ qua cú đúp được giả định và biểu thức gán được xem xét cho việc khởi tạo thành viên thứ nhất của phân nhóm con.

8.5.1 về khởi tạo tổng hợp cụ thể, vì vậy điều đó có nghĩa là Clang là chính xác để từ chối, phải không? Không quá nhanh. 8.5.4/3 nói:

List-khởi của một đối tượng hoặc tài liệu tham khảo của loại T được xác định như sau:

[...]

- Ngược lại, nếu T là một tổng hợp, tổng hợp khởi tạo được thực hiện (8.5.1).

Tôi nghĩ rằng điều đó có nghĩa là các quy tắc chính xác giống như khi khởi tạo tổng hợp, bao gồm việc cắt bỏ cú đúp, áp dụng, nghĩa là GCC là chính xác để chấp nhận.

Tôi thừa nhận, từ ngữ không rõ ràng. Vậy, trình biên dịch nào là đúng trong việc xử lý đoạn mã thứ ba? Liệu sự bỏ sót cú đúp xảy ra trong danh sách khởi tạo, hay không?

+0

đẹp câu hỏi! Nó có thể là đáng nói đến tiêu chuẩn mà bạn đang sử dụng. Tiêu chuẩn C++ 11, hoặc nếu không, dự thảo cụ thể nào. – juanchopanza

+0

"khởi tạo giống như gán" được gọi là khởi tạo sao chép. Nó gọi hàm tạo bản sao chứ không phải toán tử gán. – TemplateRex

+0

@TemplateRex: đó là lý do tôi sử dụng tác phẩm "thích". – Fanael

Trả lời

20

Áp dụng cú đúp được áp dụng, nhưng không áp dụng trong C++ 11. Trong C++ 14, chúng sẽ áp dụng vì http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1270. Nếu bạn may mắn, Clang sẽ quay trở lại chế độ C++ 11 của họ (hãy hy vọng họ sẽ làm được!).

+0

Hiện tại, 'clang-5.0' trong archlinux vẫn không hỗ trợ elace brace ngay cả với' -std = C++ 17'. –

3

liên quan: http://en.cppreference.com/w/cpp/language/aggregate_initialization

Nói tóm lại,

struct S { 
    int x; 
    struct Foo { 
     int i; 
     int j; 
     int a[3]; 
    } b; 
}; 
S s1 = { 1, { 2, 3, {4, 5, 6} } }; 
S s2 = { 1, 2, 3, 4, 5, 6}; // same, but with brace elision 
S s3{1, {2, 3, {4, 5, 6} } }; // same, using direct-list-initialization syntax 
S s4{1, 2, 3, 4, 5, 6}; // error in C++11: brace-elision only allowed with equals sign 
         // okay in C++14 
Các vấn đề liên quan