Cả clang và gcc đều chấp nhận mã sau và chọn A::operator B*
.Nên khởi tạo bởi chức năng chuyển đổi là mơ hồ khi hai ứng cử viên có cùng một trình độ cv?
struct B
{
};
struct A : B
{
operator A*();
operator B*();
};
A a;
void* x = a;
Đọc của tôi về tiêu chuẩn - câu cụ thể được đánh dấu dưới chữ in đậm - cho thấy chuyển đổi này nên mơ hồ.
Cả A::operator A*
và A::operator B*
là ứng cử viên cho giải quyết tình trạng quá tải vì A*
và B*
đều chuyển đổi thành void*
qua một chuyển đổi tiêu chuẩn. Bởi vì tham số đối tượng ngụ ý A&
là đối số duy nhất, chỉ có chuỗi chuyển đổi chuyển đổi từ đối số ngụ ý đối tượng sang tham số đối tượng ngụ ý được xem xét - loại được sinh ra bởi hàm chuyển đổi bị bỏ qua. Trong cả hai trường hợp, tham số đối tượng ngụ ý là kiểu biểu thức khởi tạo A
và tham số đối tượng ngụ ý là A&
. Nếu cả hai chuỗi chuyển đổi giống nhau, không có cách nào để phân biệt giữa hai ứng cử viên.
8,5 Initializers [dcl.init]
Ngữ nghĩa của initializers như sau. Loại đích là loại đối tượng hoặc tham chiếu là được khởi tạo và loại nguồn là loại biểu thức khởi tạo.
- Nếu loại đích là một [tài liệu tham khảo/mảng/lớp ...] [đã xóa chi tiết không áp dụng đối với kịch bản này]
- Ngược lại, nếu các loại nguồn là một (có thể cv-trình độ) loại lớp, chức năng chuyển đổi được xem xét. Các chức năng chuyển đổi áp dụng được liệt kê (13.3.1.5), và tốt nhất được chọn thông qua quá tải độ phân giải (13.3). Chuyển đổi do người dùng xác định để chọn được gọi để chuyển đổi biểu thức khởi tạo thành đối tượng đang được khởi tạo. Nếu việc chuyển đổi không thể thực hiện hoặc không rõ ràng, việc khởi tạo là không đúng định dạng.
13.3.1.5 Khởi tạo bởi chức năng chuyển đổi [over.match.conv]
Theo các điều kiện quy định tại 8.5, như một phần của một khởi của một đối tượng kiểu nonclass, một chức năng chuyển đổi có thể được viện dẫn để chuyển đổi biểu thức khởi tạo của loại lớp thành loại đối tượng đang được khởi tạo . Độ phân giải quá tải được sử dụng để chọn hàm chuyển đổi cần gọi. Giả sử rằng “CV1 T” là kiểu của đối tượng được khởi tạo, và “cv S” là kiểu của biểu thức khởi tạo, với S một loại lớp, các chức năng ứng cử viên được lựa chọn như sau:
- Các hàm chuyển đổi của S và các lớp cơ sở của nó được xem xét. Các chuyển đổi không rõ ràng các chức năng không bị ẩn trong S và loại T hoặc loại có thể được chuyển thành loại T qua chuỗi chuyển đổi chuẩn (13.3.3.1.1) là hàm ứng viên. Để khởi tạo trực tiếp, những hàm chuyển đổi rõ ràng không bị ẩn trong S và kiểu T hoặc loại có thể là được chuyển thành loại T với chuyển đổi đủ điều kiện (4.4) cũng là hàm ứng viên. Chuyển đổi các hàm trả về loại có đủ điều kiện cv được coi là mang lại phiên bản không đủ tiêu chuẩn của loại đó cho quá trình chọn chức năng ứng cử viên này. Hàm chuyển đổi trả về “giá trị trả về cv2 X” trả về giá trị hoặc xvalues, tùy thuộc vào loại tham chiếu, thuộc loại “cv2 X” và do đó được coi là mang lại X cho quá trình chọn các hàm ứng cử viên.
Danh sách đối số có một đối số, là biểu thức khởi tạo. [Lưu ý: Đối số này sẽ là so với tham số đối tượng ẩn của hàm chuyển đổi. —end note]
Điều này có mơ hồ theo tiêu chuẩn không?
EDIT: lưu ý rằng đây là một câu hỏi tương tự, nhưng không giống như Distinguishing between user-defined conversion sequences by the initial standard conversion sequence
Sự khác biệt là trong ví dụ của tôi cả hai chức năng chuyển đổi có trình độ tương tự.
Cả hai chức năng chuyển đổi trở về một con trỏ đến địa chỉ cơ sở cùng một ví dụ mà chuyển đổi thành 'void *' gây ra. Thử đa thừa kế và toán tử chuyển đổi bổ sung và chuyển đổi sẽ không rõ ràng. –
@CaptainObvlious Làm thế nào để bạn biết những gì họ quay trở lại? [Họ thậm chí không cần phải được thực hiện để kiểm tra câu hỏi này] (http://coliru.stacked-crooked.com/view?id=ad1ba686b7a271079f6ca6c5e91f5c02-e1204655eaff68246b392dc70c5a32c9). – Casey
@Casey Vì toán tử chuyển đổi có loại trả về xác định những gì chúng trả về. –