2015-04-23 13 views
17

GCC (thử nghiệm với 4,9) chấp nhận các testcase sau:quá tải chênh lệch độ phân giải giữa gcc và kêu vang liên quan đến xây dựng di chuyển và 'nguồn gốc (Base &&)' constructor

struct Base {}; 

struct Derived : Base { 
    Derived(); 
    explicit Derived(const Derived&); 
    explicit Derived(Derived&&); 
    explicit Derived(const Base&); 
    Derived(Base&&); 
}; 

Derived foo() { 
    Derived result; 
    return result; 
} 

int main() { 
    Derived result = foo(); 
} 

Clang (thử nghiệm với 3.5) từ chối yêu cầu như sau thông báo lỗi:

test.cpp:13:10: error: no matching constructor for initialization of 'Derived' 
    return result; 
     ^~~~~~ 
test.cpp:8:5: note: candidate constructor not viable: no known conversion from 'Derived' to 'Base &&' for 1st argument 
    Derived(Base&&); 
    ^
test.cpp:4:5: note: candidate constructor not viable: requires 0 arguments, but 1 was provided 
    Derived(); 
    ^

Ai là đúng?

Trả lời

14

Tôi tin rằng Clang chính xác ở đây. GCC không nên chấp nhận mã.

Lý do là cách giải quyết tình trạng quá tải cho nhà thầu cho các bản sao đối tượng xảy ra trong một tuyên bố return được quy định tại [class.copy] p32 (tôi nhấn mạnh):

Khi các tiêu chuẩn cho sự bỏ bớt một constructor sao chép/di chuyển được đáp ứng , [...] và đối tượng cần sao chép được chỉ định bởi một giá trị, [...], độ phân giải quá tải để chọn hàm tạo cho bản sao trước tiên là được thực hiện như thể đối tượng được chỉ định bằng giá trị. Nếu độ phân giải quá tải đầu tiên không thành công hoặc không được thực hiện, hoặc nếu loại thông số đầu tiên của hàm tạo đã chọn không phải là một tham chiếu tham chiếu đến loại đối tượng (có thể cv đủ điều kiện), quá tải độ phân giải , xem xét đối tượng như một giá trị.

Trong ví dụ này, các tiêu chí cho phép cắt bỏ được đáp ứng (bởi dấu đầu tiên trong [class.copy] p31) và đối tượng được sao chép được chỉ định bởi một giá trị, vì vậy đoạn này áp dụng.

Độ phân giải quá tải lần đầu tiên được thử như thể đối tượng được chỉ định bởi một giá trị. Các nhà xây dựng explicit không phải là ứng cử viên (xem bên dưới để giải thích lý do), do đó, nhà xây dựng Derived(Base&&) được chọn. Tuy nhiên, điều này nằm dưới "kiểu tham số đầu tiên của hàm tạo đã chọn không phải là tham chiếu rvalue đối với kiểu của đối tượng" (thay vào đó, nó là tham chiếu rvalue cho kiểu lớp cơ sở của đối tượng), vì vậy độ phân giải quá tải sẽ được thực hiện lại , xem xét đối tượng như một giá trị.

Độ phân giải quá tải thứ hai này không thành công, bởi vì hàm tạo duy nhất (một lần nữa, các hàm tạo explicit không phải là ứng viên) có tham số tham chiếu rvalue, không thể liên kết với lvalue. Clang hiển thị lỗi lỗi độ phân giải quá tải kết quả.


Để hoàn thành việc giải thích, đây là lý do tại sao explicit nhà xây dựng không phải là ứng cử viên cho một trong hai độ phân giải quá tải (tất cả nhấn mạnh là của tôi).

Thứ nhất, [dcl.init] p15 nói rằng:

Việc khởi xảy ra trong = hình thức của một cú đúp-hoặc-bằng-initializer hoặc trạng (6.4), cũng như trong tranh luận đi qua, chức năng trả về, ném một ngoại lệ (15.1), xử lý một ngoại lệ (15.3), và tổng hợp thành viên khởi tạo (8.5.. 1), là gọi sao chép khởi"

Tiếp theo, chúng ta nhìn vào [over.match.ctor] p1:

Đối với bản sao-khởi, các chức năng ứng cử viên là tất cả các chuyển đổi nhà thầu (12.3.1) của lớp đó.

Cuối cùng, chúng ta thấy rằng explicit nhà xây dựng không được chuyển đổi nhà xây dựng trong [class.conv.ctor] p1:

Một constructor tuyên bố mà không chức năng-specifier explicit chỉ định giá chuyển đổi từ các loại thông số của nó để loại của nó lớp học. Nhà xây dựng như vậy được gọi là chuyển đổi hàm tạo.

+0

Nhưng nó nói "nếu loại nếu thông số đầu tiên không phải là tham chiếu rvalue, nó sẽ được thực hiện lại". Vì vậy, vì nó là, độ phân giải quá tải không được thực hiện một lần nữa. – Columbo

+0

@Columbo: Nó nói "nếu loại tham số đầu tiên không phải là tham chiếu rvalue ** đối với loại của đối tượng **", độ phân giải quá tải được thực hiện lại. Ở đây, nó là một tham chiếu rvalue, nhưng không phải là kiểu của đối tượng. (Lưu ý rằng "đối tượng" ở đây đề cập đến "đối tượng được sao chép" từ đầu đoạn văn, đó là một đối tượng thuộc loại 'Có nguồn gốc'.) – HighCommander4

+0

Ahh, đúng, đúng. – Columbo

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