Helpex - Trao đổi & giúp đỡ Đăng nhập
17

GCC (được thử nghiệm với 4.9) chấp nhận các testcase sau:

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 (được thử nghiệm với 3.5) từ chối nó với thông báo lỗi sau:

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 đúng?

17 hữu ích 0 bình luận 906 xem chia sẻ
14

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

Lý do là cách giải quyết quá tải cho các hàm tạo cho bản sao đối tượng xảy ra trong một returncâu lệnh được chỉ định trong [class.copy] p32(mỏ nhấn mạnh):

Khi các tiêu chí để loại bỏ một hàm tạo sao chép / di chuyển được đáp ứng, [...] và đối tượng được sao chép được chỉ định bởi một giá trị, [...], việc phân giải quá tải để chọn hàm tạo cho bản sao được thực hiện đầu tiên như thể đối tượng được chỉ định bởi một giá trị. Nếu giải quyết 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 kiểu của tham số đầu tiên của hàm tạo đã chọn không phải là tham chiếu rvalue cho kiểu của đối tượng (có thể đủ điều kiện cv) , thì giải quyết quá tải sẽ được thực hiện lại, coi đối tượng là một giá trị.

Trong ví dụ này, các tiêu chí về loại bỏ được đáp ứng (bởi dấu đầu dòng đầu tiên [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.

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

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


Để hoàn thành lời giải thích, đây là lý do tại sao các hàm explicittạo không phải là ứng cử viên cho giải pháp quá tải (tất cả sự nhấn mạnh là của tôi).

Đầu tiên, hãy [dcl.init] p15nói rằng:

Việc khởi tạo xảy ra ở dạng = của bộ khởi tạo hoặc điều kiện dấu ngoặc nhọn (6.4), cũng như trong truyền đối số, trả về hàm , ném ngoại lệ (15.1), xử lý ngoại lệ (15.3) và tổng hợp thành viên khởi tạo (8.5.1), được gọi là sao chép-khởi tạo . "

Tiếp theo, chúng ta xem xét [over.match.ctor] p1:

Đối với khởi tạo sao chép , các hàm ứng cử viên là tất cả các hàm tạo chuyển đổi (12.3.1) của lớp đó.

Cuối cùng, chúng ta thấy rằng các hàm explicittạo không chuyển đổi các hàm tạo trong [class.conv.ctor] p1:

Một phương thức khởi tạo được khai báo mà không có hàm-specifier chỉ explicit định một chuyển đổi từ các kiểu tham số của nó thành kiểu của lớp của nó. Một hàm tạo như vậy được gọi là một hàm tạo chuyển đổi .

14 hữu ích 3 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ c++ c++11 gcc clang overload-resolution , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading