2015-02-25 13 views
9

Tôi đã chơi với một số mã vô dụng để hiểu khởi của tài liệu tham khảo thành viên, và tình cờ gặp này:khởi của thành viên tham chiếu const trong danh sách initializer

struct A {}; 

struct B 
{ 
    B() : a() 
    { 
    } 

    const A& a; 
}; 

Đoạn mã trên cung cấp cho các lỗi sau khi biên dịch với gcc 4.9. 2:

In constructor 'B::B()': 
error: value-initialization of reference type 'const A&' 
    B() : a() 

Tôi hiểu điều này.

Nhưng nếu tôi sử dụng khởi tạo thống nhất trong danh sách initializer constructor của B, như vậy:

struct A {}; 

struct B 
{ 
    B() : a{} 
    { 
    } 

    const A& a; 
}; 

Nó biên dịch tốt.

Vì vậy, câu hỏi là, tại sao việc sử dụng đồng bộ hóa khởi tạo ở đây thay đổi kết quả biên dịch?

Tôi cũng đã cố gắng này với Microsoft Visual C++ 2013. Nó không biên dịch hoặc phiên bản mã, với thông báo lỗi tương tự:

Error 3 error C2440: 'initializing' : cannot convert from 'int' to 'const A & 

Bạn có thể có một vở kịch nhanh chóng với nó ở đây:

http://ideone.com/7f2t8I

+1

Khởi chạy đồng bộ là một tính năng tương đối mới và bạn phải mong đợi một số lỗi trình biên dịch với nó. Trong trường hợp này, không tìm kiếm nó, tôi đoán rằng trình biên dịch của Microsoft là chính xác. –

+2

Đoán của tôi: '{}' được hiểu là lời gọi hàm khởi tạo mặc định của 'A' (giống như bạn đã làm' A a {}; '), do đó tạm thời' A {} 'được tạo. Sau đó nó được ràng buộc với const-ref và tuổi thọ của nó được mở rộng (như nếu bạn đã làm 'const A & a {}', cũng hoạt động trong GCC). Nhưng tôi không biết tiêu chuẩn nói gì về điều đó; nếu nó được cho phép ... Điều gì thực sự gây nhầm lẫn cho tôi là MSVC nhìn thấy một 'int' mà tôi không thể nhìn thấy ... Bạn đã thực sự biên dịch mã này? – leemes

+0

@JamesKanze Tôi hiểu điều đó, nhưng tôi không muốn đi ra ngoài và hét lên lỗi trình biên dịch. Có lẽ có một cái gì đó về khởi tạo thống nhất mà tôi không biết và điều đó sẽ làm cho nó hoạt động khác nhau trong tình huống này. – Hugo

Trả lời

6

GCC đúng trong cách hiểu là {}. [Dcl.init.list] /p3.8-9 (trích dẫn N4296; bản thảo đầu tiên có thứ tự tương đối giống nhau của hai viên đạn này):

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 định nghĩa là sau:

  • [7 viên đạn không áp dụng bỏ qua]

  • Ngược lại, nếu T là một loại tài liệu tham khảo, một tạm thời prvalue của các loại tham chiếu bởi T là copy-list-khởi tạo hoặc trực tiếp-danh sách-khởi tạo, tùy thuộc vào loại khởi tạo cho tham chiếu, và tham chiếu được ràng buộc để tạm thời đó. [Lưu ý: Như thường lệ, ràng buộc sẽ không thành công và chương trình bị hỏng nếu loại tham chiếu là tham chiếu giá trị không thành một loại không phải const. - lưu ý cuối ]

  • Nếu không, nếu danh sách trình khởi tạo không có phần tử, đối tượng sẽ được khởi tạo giá trị.

Liệt kê khởi tạo lần truy cập tham chiếu bullet 3.8, gây tạm thời. Trường hợp khởi tạo giá trị, trong 3.9, không áp dụng.

giá trị khởi tạo của một tài liệu tham khảo là vô hình thành ([dcl.init]/p9):

Một chương trình mà các cuộc gọi cho mặc định-khởi tạo hoặc giá trị khởi tạo của một thực thể của kiểu tham chiếu là không thành hình.


Tuy nhiên, tính đến N4296, mỗi [class.base.init]/p8:

Một biểu thức tạm thời ràng buộc với một thành viên tham chiếu trong một mem-initializer bị ốm - hình thành.

Điều này đã được thêm vào là kết quả của CWG issue 1696, là DR (báo cáo lỗi) so với C++ 14.

Pre-CWG1696, tiêu chuẩn với điều kiện (N4140 [class.temporary] /p5.1):

Một tạm thời bị ràng buộc cho một thành viên tham chiếu trong một constructor ctor-initializer (12,6. 2) vẫn còn cho đến khi các nhà xây dựng thoát.

có nghĩa là tham chiếu sẽ trở nên lơ lửng ngay sau khi xây dựng. Quyết định này có lẽ thúc đẩy CWG1696 không cho phép các ràng buộc như vậy hoàn toàn.

+0

Tôi giả định N4296 là C++ 14. Vì vậy, cuối cùng họ đã sửa chữa một cái gì đó đã được một vấn đề (IMHO) kể từ C + + 98. –

+0

@JamesKanze N4140 là C++ 14. CWG 1696 là một DR chống lại C++ 14, tuy nhiên, do đó vẫn nên được thực hiện bởi trình biên dịch trong chế độ C++ 14. –

+0

Có trình biên dịch nào có chế độ C++ 14 hoàn toàn phù hợp không? (Đối với vấn đề đó, không có bất kỳ một chế độ C++ 11 hoàn toàn phù hợp?) –

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