Tôi tin rằng những thứ này về cơ bản sôi xuống [temp.inst] / 2 (nhấn mạnh của tôi):
Việc khởi tạo ngầm định của chuyên môn hóa mẫu lớp gây ra việc khởi tạo ngầm định các khai báo, nhưng không phải là các định nghĩa , đối số mặc định hoặc các chỉ định noexcept của các hàm thành viên lớp, các lớp thành viên, liệt kê thành viên có phạm vi, các thành viên dữ liệu tĩnh , các mẫu thành viên và bạn bè; [Càng]
và [temp.inst] / 9
Việc triển khai sẽ không được khởi tạo ngầm [[]] một thành viên dữ liệu tĩnh của mẫu lớp [trừ] trừ khi việc khởi tạo đó là bắt buộc.
Các từ ngữ trong tiêu chuẩn liên quan đến khởi tạo mẫu ẩn để lại nhiều chi tiết mở cho việc giải thích. Nói chung, dường như với tôi rằng bạn chỉ đơn giản là không thể dựa vào các phần của mẫu không được khởi tạo trừ khi thông số kỹ thuật nói rõ ràng như vậy. Như vậy:
Đoạn trích số 1
Q. Tại sao mã này biên dịch? Không phải chúng ta bắt đầu A khi thừa kế từ B sao? Không có VD trong B, vậy trình biên dịch có nên đưa ra lỗi ở đây không?
Bạn đang bắt đầu A<B>
. Nhưng khởi tạo A<B>
chỉ khởi tạo các khai báo, không phải định nghĩa của các thành viên dữ liệu tĩnh của nó. VB
không bao giờ được sử dụng theo cách đòi hỏi một định nghĩa để tồn tại. Trình biên dịch nên chấp nhận mã này.
Đoạn trích số 2
Q. Tại sao nó biên dịch với gcc9 / tại sao nó không biên dịch với clang9?
Như Jarod42 đã chỉ ra, tuyên bố AB
chứa loại giữ chỗ. Dường như với tôi rằng từ ngữ của tiêu chuẩn không thực sự rõ ràng về những gì sẽ xảy ra ở đây. Việc khởi tạo khai báo của một thành viên dữ liệu tĩnh có chứa khấu trừ loại giữ chỗ kích hoạt loại giữ chỗ và do đó, tạo thành một sử dụng đòi hỏi định nghĩa của thành viên dữ liệu tĩnh? Tôi không thể tìm thấy từ ngữ trong tiêu chuẩn có thể nói rõ ràng có hoặc không với điều đó. Vì vậy, tôi muốn nói rằng cả hai cách giải thích đều có giá trị như nhau ở đây và do đó, GCC và clang đều đúng
Đoạn số 3
Q. Nếu cấu trúc B không đầy đủ ở đây thì tại sao nó không hoàn chỉnh trong đoạn số 2?
Một loại lớp chỉ hoàn thành tại điểm mà bạn đạt đến kết thúc }
của trình xác định lớp [class.mem] / 6 . Do đó, B
không đầy đủ trong quá trình khởi tạo ngầm A<B>
trong tất cả các đoạn của bạn. Chỉ là điều này không liên quan đến Snippet # 1. Trong Snippet # 2, No member named AD in B
kết quả là clang đã gây ra lỗi cho bạn . Tương tự như trường hợp của Snippet # 2, tôi không thể tìm thấy từ ngữ khi chính xác các khai báo bí danh thành viên sẽ được khởi tạo. Tuy nhiên, không giống như định nghĩa của các thành viên dữ liệu tĩnh, không có từ ngữ nào để ngăn chặn rõ ràng việc khởi tạo các khai báo bí danh thành viên trong quá trình khởi tạo ngầm định của mẫu lớp. Vì vậy, tôi sẽ nói rằng hành vi của cả GCC và clang là một cách giải thích hợp lệ của tiêu chuẩn trong trường hợp này
struct B
instantiatingA
vớiB
?