Tại sao C ++ 11 làm cho các hàm " delete
d" tham gia vào việc phân giải quá tải ?
Tại sao điều này lại hữu ích? Hay nói cách khác, tại sao chúng lại bị ẩn thay vì bị xóa hoàn toàn?
Tại sao C ++ 11 làm cho các hàm " delete
d" tham gia vào việc phân giải quá tải ?
Tại sao điều này lại hữu ích? Hay nói cách khác, tại sao chúng lại bị ẩn thay vì bị xóa hoàn toàn?
Câu trả lời:
Một nửa mục đích của = delete
cú pháp là có thể ngăn mọi người gọi một số hàm với các tham số nhất định. Điều này chủ yếu là để ngăn chặn chuyển đổi ngầm trong một số trường hợp cụ thể. Để cấm quá tải cụ thể, nó phải tham gia vào việc giải quyết quá tải.
Câu trả lời mà bạn trích dẫn cho bạn một ví dụ hoàn hảo:
struct onlydouble {
onlydouble(std::intmax_t) = delete;
onlydouble(double);
};
Nếu delete
loại bỏ hoàn toàn hàm, điều đó sẽ làm cho = delete
cú pháp tương đương như sau:
struct onlydouble2 {
onlydouble2(double);
};
Bạn có thể làm điều này:
onlydouble2 val(20);
Đây là C ++ hợp pháp. Trình biên dịch sẽ xem xét tất cả các hàm tạo; không ai trong số họ trực tiếp lấy kiểu số nguyên. Nhưng một trong số họ có thể lấy nó sau khi chuyển đổi ngầm. Vì vậy, nó sẽ gọi như vậy.
onlydouble val(20);
Đây không phải là C ++ hợp pháp. Trình biên dịch sẽ xem xét tất cả các hàm tạo, bao gồm cả các hàm delete
d. Nó sẽ thấy một kết quả khớp chính xác, thông qua std::intmax_t
(sẽ khớp chính xác với bất kỳ chữ số nguyên nào). Vì vậy, trình biên dịch sẽ chọn nó và sau đó ngay lập tức đưa ra lỗi, vì nó đã chọn một delete
hàm d.
= delete
có nghĩa là "Tôi cấm điều này," không chỉ đơn thuần, "Điều này không tồn tại." Đó là một tuyên bố mạnh mẽ hơn nhiều.
Tôi đã hỏi tại sao tiêu chuẩn C ++ nói = xóa có nghĩa là "Tôi cấm điều này" thay vì "điều này không tồn tại"
Đó là bởi vì chúng ta không cần ngữ pháp đặc biệt để nói "điều này không tồn tại." Chúng tôi hiểu ngầm điều này bằng cách không khai báo "this" cụ thể được đề cập. "Tôi cấm điều này" đại diện cho một cấu trúc không thể đạt được nếu không có ngữ pháp đặc biệt. Vì vậy, chúng tôi nhận được ngữ pháp đặc biệt để nói "Tôi cấm điều này" chứ không phải điều khác.
Chức năng duy nhất mà bạn có được khi có một ngữ pháp rõ ràng "cái này không tồn tại" sẽ là ngăn ai đó sau này tuyên bố nó tồn tại. Và điều đó không đủ hữu ích để cần có ngữ pháp riêng.
nếu không thì không có cách nào để tuyên bố rằng hàm tạo bản sao không tồn tại và sự tồn tại của nó có thể gây ra sự mơ hồ vô nghĩa.
Hàm tạo bản sao là một hàm thành viên đặc biệt. Mỗi lớp luôn có một hàm tạo bản sao. Cũng giống như chúng luôn có toán tử gán bản sao, hàm tạo di chuyển, v.v.
Các chức năng này tồn tại; câu hỏi chỉ là liệu việc gọi họ có hợp pháp hay không. Nếu bạn cố gắng nói điều đó = delete
có nghĩa là chúng không tồn tại, thì thông số kỹ thuật sẽ phải giải thích ý nghĩa của việc một hàm không tồn tại. Đây không phải là một khái niệm mà đặc tả xử lý.
Nếu bạn cố gắng gọi một hàm chưa được khai báo / định nghĩa, thì trình biên dịch sẽ bị lỗi. Nhưng nó sẽ lỗi do một số nhận dạng không xác định , không phải do lỗi "hàm không tồn tại" (ngay cả khi trình biên dịch của bạn báo cáo theo cách đó). Các hàm tạo khác nhau đều được gọi bằng độ phân giải quá tải, do đó, "sự tồn tại" của chúng được xử lý về mặt đó.
Trong mọi trường hợp, có một hàm được khai báo thông qua mã định danh hoặc một hàm tạo / hủy (cũng được khai báo thông qua mã định danh, chỉ là một mã định danh kiểu). Việc nạp chồng toán tử ẩn định danh đằng sau đường cú pháp, nhưng nó vẫn ở đó.
Đặc tả C ++ không thể xử lý khái niệm "hàm không tồn tại". Nó có thể xử lý sự không khớp quá tải. Nó có thể xử lý sự mơ hồ quá tải. Nhưng nó không biết về những gì không có ở đó. Vì vậy, = delete
được định nghĩa theo nghĩa "nỗ lực gọi đây là thất bại" hữu ích hơn nhiều so với "giả vờ như tôi chưa bao giờ viết dòng này".
Và một lần nữa, hãy đọc lại phần đầu tiên. Bạn không thể làm điều đó với "chức năng không tồn tại." Đó là một lý do khác tại sao nó được định nghĩa theo cách đó: bởi vì một trong những trường hợp sử dụng chính của = delete
cú pháp là có thể buộc người dùng sử dụng một số loại tham số nhất định, ép kiểu rõ ràng, v.v. Về cơ bản, để loại bỏ các chuyển đổi kiểu ngầm.
Đề xuất của bạn sẽ không làm được điều đó.
= delete
có nghĩa là "thành viên này không tồn tại", có nghĩa là nó không thể tham gia giải quyết quá tải.
= delete
có nghĩa là "thành viên này không tồn tại", thì ví dụ đầu tiên tôi đã đăng sẽ không thể ngăn mọi người chuyển số nguyên sang hàm tạo onlydouble
của , vì onlydouble
quá tải bị xóa sẽ không tồn tại . Nó sẽ không tham gia vào quá trình phân giải quá tải, và do đó nó sẽ không ngăn bạn chuyển các số nguyên. Đó là một nửa điểm của = delete
cú pháp: để có thể nói, "Bạn không thể chuyển X ngầm định cho hàm này."
=delete
? Rốt cuộc, chúng ta có thể nói "không thể sao chép" bằng cách thực hiện điều tương tự: khai báo hàm tạo / phép gán bản sao là riêng tư. Ngoài ra, lưu ý rằng việc khai báo điều gì đó riêng tư không làm cho nó không thể gọi được; mã trong lớp vẫn có thể gọi nó. Vì vậy, nó không giống như = delete
. Không, = delete
cú pháp cho phép chúng ta thực hiện một điều gì đó rất bất tiện và khó hiểu trước đây theo cách rõ ràng và hợp lý hơn nhiều.
Dự thảo làm việc C ++ 2012-11-02 không cung cấp cơ sở lý luận đằng sau quy tắc này, chỉ là một số ví dụ
8.4.3 Các định nghĩa đã xóa [dcl.fct.def.delete]
...
3 [ Ví dụ : Người ta có thể thực thi khởi tạo không mặc định và khởi tạo không tích phân với
struct onlydouble {
onlydouble() = delete; // OK, but redundant
onlydouble(std::intmax_t) = delete;
onlydouble(double);
};
- end example ]
[ Ví dụ : Người ta có thể ngăn chặn việc sử dụng một lớp trong các biểu thức mới nhất định bằng cách sử dụng các định nghĩa đã xóa của toán tử do người dùng khai báo mới cho lớp đó.
struct sometype {
void *operator new(std::size_t) = delete;
void *operator new[](std::size_t) = delete;
};
sometype *p = new sometype; // error, deleted class operator new
sometype *q = new sometype[3]; // error, deleted class operator new[]
- end example ]
[ Ví dụ : Người ta có thể làm cho một lớp không thể sao chép, tức là chỉ di chuyển, bằng cách sử dụng các định nghĩa đã xóa của hàm tạo bản sao và toán tử gán sao chép, sau đó cung cấp các định nghĩa mặc định của hàm tạo di chuyển và toán tử gán di chuyển.
struct moveonly {
moveonly() = default;
moveonly(const moveonly&) = delete;
moveonly(moveonly&&) = default;
moveonly& operator=(const moveonly&) = delete;
moveonly& operator=(moveonly&&) = default;
~moveonly() = default;
};
moveonly *p;
moveonly q(*p); // error, deleted copy constructor
- cuối ví dụ ]