Ngắn
Hàm chuyển đổi operator int()
được chọn bởi clang operator bool() const
vì b
const không đủ điều kiện, trong khi toán tử chuyển đổi cho bool là.
Lý do ngắn gọn là các chức năng ứng cử viên cho giải quyết tình trạng quá tải (với tham số đối tượng tiềm ẩn tại chỗ), khi chuyển đổi b
để bool
là
operator bool (B2 const &);
operator int (B2 &);
trong đó cái thứ hai là một trận đấu tốt hơn vì b
const không đủ điều kiện.
Nếu cả hai chức năng có cùng tiêu chuẩn (cả hai const
hoặc không), operator bool
được chọn vì nó cung cấp chuyển đổi trực tiếp.
Chuyển đổi qua ký hiệu truyền, được phân tích từng bước
Nếu chúng ta đồng ý rằng ostream Inserter boolean (std :: basic_ostream :: operator << (bool val) theo [ostream.inserters.arithmetic]) được gọi với giá trị mà kết quả từ một sự chuyển đổi của b
để bool
chúng ta có thể thâm nhập vào chuyển đổi .
1. Biểu cảm diễn viên
Dàn diễn viên của b to bool
(bool)b
đánh giá
static_cast<bool>(b)
theo C ++ 11, 5.4 / 4 [expr.cast] vì const_cast
không áp dụng được (không thêm hoặc bớt const ở đây).
Chuyển đổi tĩnh này được phép cho mỗi C ++ 11, 5.2.9 / 4 [expr.static.cast] , nếu bool t(b);
đối với một biến được phát minh t được định dạng tốt. Các câu lệnh như vậy được gọi là khởi tạo trực tiếp theo C ++ 11, 8.5 / 15 [dcl.init] .
2. Khởi tạo trực tiếp bool t(b);
Khoản 16 của các trạng thái đoạn tiêu chuẩn ít được đề cập nhất (tôi nhấn mạnh):
Ngữ nghĩa của các bộ khởi tạo như sau. Kiểu đích là kiểu của đối tượng hoặc tham chiếu đang được khởi tạo và kiểu nguồn là kiểu của biểu thức trình khởi tạo.
[...]
[...] nếu kiểu nguồn là kiểu lớp (có thể đủ tiêu chuẩn cv) , các hàm chuyển đổi được xem xét.
Các chức năng chuyển đổi áp dụng được liệt kê và chức năng tốt nhất được chọn thông qua giải quyết quá tải.
2.1 Có những chức năng chuyển đổi nào?
Các hàm chuyển đổi có sẵn operator int ()
và operator bool() const
vì như C ++ 11, 12.3 / 5 [class.conv] cho chúng ta biết:
Một hàm chuyển đổi trong lớp dẫn xuất không ẩn một hàm chuyển đổi trong một lớp cơ sở trừ khi hai hàm chuyển đổi về cùng một kiểu.
Trong khi C ++ 11, 13.3.1.5/1 [over.match.conv] cho biết:
Các hàm chuyển đổi của S và các lớp cơ sở của nó được xem xét.
trong đó S là lớp sẽ được chuyển đổi từ.
2.2 Các chức năng chuyển đổi nào được áp dụng?
C ++ 11, 13.3.1.5/1 [over.match.conv] (mỏ nhấn mạnh):
1 [...] Giả sử rằng “cv1 T” là kiểu của đối tượng đang được khởi tạo và “cv S” là kiểu của biểu thức khởi tạo, với S là kiểu lớp, các hàm ứng cử viên được chọn như sau: các chức năng của S và các lớp cơ sở của nó được xem xét. Các hàm chuyển đổi không rõ ràng không bị ẩn trong S và loại năng suất T hoặc một loại có thể được chuyển đổi thành loại T thông qua trình tự chuyển đổi tiêu chuẩn là các hàm ứng viên.
Do đó operator bool () const
có thể áp dụng vì nó không bị ẩn bên trong B2
và tạo ra a bool
.
Phần được nhấn mạnh trong trích dẫn tiêu chuẩn cuối cùng có liên quan đến chuyển đổi sử dụng operator int ()
vì int
là một loại có thể được chuyển đổi thành bool thông qua trình tự chuyển đổi tiêu chuẩn. Chuyển đổi từ int
thành bool
thậm chí không phải là một chuỗi mà là một chuyển đổi trực tiếp đơn giản được phép theo C ++ 11, 4,12 / 1 [tr.b.bool]
Giá trị pr của kiểu số học, kiểu liệt kê, con trỏ hoặc con trỏ đến kiểu thành viên có thể được chuyển đổi thành giá trị pr kiểu bool. Giá trị 0, giá trị con trỏ null hoặc giá trị con trỏ thành viên null được chuyển đổi thành false; bất kỳ giá trị nào khác được chuyển đổi thành true.
Điều này có nghĩa là điều đó operator int ()
cũng có thể áp dụng được.
2.3 Chọn chức năng chuyển đổi nào?
Việc lựa chọn chức năng chuyển đổi thích hợp được thực hiện thông qua độ phân giải quá tải ( C ++ 11, 13.3.1.5/1 [over.match.conv] ):
Độ phân giải quá tải được sử dụng để chọn chức năng chuyển đổi được gọi.
Có một điều "khó hiểu" đặc biệt khi nói đến giải quyết quá tải cho các hàm thành viên của lớp: tham số đối tượng ngầm định ".
Theo C ++ 11, 13.3.1 [over.match.funcs] ,
[...] cả hàm thành viên tĩnh và không tĩnh đều có một tham số đối tượng ngầm định [...]
trong đó loại tham số này cho các hàm thành viên không tĩnh - theo điều khoản 4 là:
trong đó X là lớp mà hàm là thành viên và cv là cấp độ cv trên khai báo hàm thành viên.
Điều này có nghĩa là (theo C ++ 11, 13.3.1.5/2 [over.match.conv] ), trong một lần khởi tạo bằng hàm chuyển đổi,
Danh sách đối số [t] he có một đối số, đó là biểu thức khởi tạo. [Lưu ý: Đối số này sẽ được so sánh với tham số đối tượng ngầm định của các hàm chuyển đổi. —Gửi ghi chú]
Các hàm ứng cử viên để giải quyết quá tải là:
operator bool (B2 const &);
operator int (B2 &);
Rõ ràng, operator int ()
là một kết quả phù hợp hơn nếu một chuyển đổi được yêu cầu bằng cách sử dụng một đối tượng không cố định của loại B2
vì operator bool ()
yêu cầu chuyển đổi đủ điều kiện.
Nếu cả hai hàm chuyển đổi có cùng tiêu chuẩn const, thì việc giải quyết quá tải của các hàm đó sẽ không còn hiệu quả nữa. Trong trường hợp này, xếp hạng chuyển đổi (trình tự) được đưa ra.
3. Tại sao lại được operator bool ()
chọn khi cả hai hàm chuyển đổi có cùng tiêu chuẩn const?
Chuyển đổi từ B2
sang bool
là một chuỗi chuyển đổi do người dùng xác định ( C ++ 11, 13.3.3.1.2 / 1 [over.ics.user] )
Trình tự chuyển đổi do người dùng xác định bao gồm trình tự chuyển đổi tiêu chuẩn ban đầu, tiếp theo là chuyển đổi do người dùng xác định, sau đó là trình tự chuyển đổi tiêu chuẩn thứ hai.
[...] Nếu chuyển đổi do người dùng xác định được chỉ định bởi một hàm chuyển đổi, thì trình tự chuyển đổi tiêu chuẩn ban đầu sẽ chuyển đổi kiểu nguồn thành tham số đối tượng ngầm định của hàm chuyển đổi.
C ++ 11, 13.3.3.2/3 [over.ics.rank]
[...] xác định thứ tự từng phần của chuỗi chuyển đổi ngầm định dựa trên các mối quan hệ trình tự chuyển đổi tốt hơn và chuyển đổi tốt hơn.
[...] Trình tự chuyển đổi do người dùng xác định U1 là trình tự chuyển đổi tốt hơn trình tự chuyển đổi khác do người dùng xác định U2 nếu chúng chứa cùng hàm chuyển đổi do người dùng xác định hoặc phương thức khởi tạo hoặc khởi tạo tổng hợp và trình tự chuyển đổi tiêu chuẩn thứ hai của U1 tốt hơn trình tự chuyển đổi tiêu chuẩn thứ hai của U2.
Việc chuyển đổi tiêu chuẩn thứ hai là trường hợp operator bool()
là bool
để bool
(chuyển đổi danh tính) trong khi việc chuyển đổi tiêu chuẩn thứ hai trong trường hợp operator int ()
là int
để bool
đó là một sự chuyển đổi boolean.
Do đó, trình tự chuyển đổi, bằng cách sử dụng operator bool ()
, sẽ tốt hơn nếu cả hai hàm chuyển đổi có cùng tiêu chuẩn const.