Đầu tiên, tại sao lại thu hẹp? Điều đó xuất phát từ §5/10:
Nhiều toán tử nhị phân mong đợi toán hạng hoặc số đếm gây ra chuyển đổi và loại kết quả lợi nhuận theo cách tương tự. Mục đích là để mang lại một loại phổ biến, đó cũng là loại kết quả. Mô hình này được gọi là chuyển đổi số học thông thường, được định nghĩa như sau:
- [..]
- Nếu không, các chương trình khuyến mãi không thể thiếu (4.5) phải được thực hiện trên cả hai toán hạng.
nơi khuyến mãi không thể thiếu được định nghĩa trong 4.5/1:
Một prvalue của một kiểu số nguyên khác hơn bool
, char16_t
, char32_t
, hoặc wchar_t
có số nguyên chuyển đổi cấp bậc (4.13) thấp hơn xếp hạng của int
có thể được chuyển đổi thành giá trị của loại int
nếu int
có thể đại diện cho tất cả các giá trị của loại nguồn; nếu không, giá trị prvalue nguồn có thể được chuyển đổi thành giá trị của loại unsigned int
.
Trong trường hợp của chúng tôi sau đó, chúng tôi có decltype(char + char)
là int
vì rank chuyển đổi char
's ít hơn int
vì vậy cả hai được thăng int
trước khi cuộc gọi đến operator+
.Bây giờ, chúng tôi có int
s mà chúng tôi đang chuyển đến một nhà xây dựng mất char
s. Theo định nghĩa (§8.5.4/7, cụ thể 7.4):
Một thu hẹp chuyển đổi là một chuyển đổi ngầm
(7,4) - từ một loại nguyên hoặc kiểu enumeration unscoped để một kiểu số nguyên không thể đại diện cho tất cả các giá trị của kiểu gốc, ngoại trừ nơi nguồn là một biểu thức liên tục có giá trị sau khi các quảng cáo tích phân sẽ phù hợp với loại mục tiêu.
được một cách rõ ràng bị cấm trong danh sách-khởi tạo cụ thể như mỗi §8.5.4/3 (tôi nhấn mạnh, các "xem dưới đây" thực sự đề cập đến những gì tôi chỉ cần sao chép ở trên):
List- khởi tạo của một đối tượng hoặc tài liệu tham khảo của loại T
được định nghĩa như sau
- [..]
- Ngược lại, nếu T
là một loại lớp, nhà thầu được xem xét. Các nhà thầu được áp dụng được liệt kê và được chọn tốt nhất thông qua độ phân giải quá tải (13.3, 13.3.1.7). Nếu một chuyển đổi thu hẹp (xem bên dưới) là cần thiết để chuyển đổi bất kỳ đối số nào, chương trình bị lỗi. [...]
Đây là lý do tại sao số vec3<T>{int, int, int}
của bạn cho bạn cảnh báo: chương trình khuyến mãi số nguyên yêu cầu thu hẹp chuyển đổi trên tất cả các biểu thức. Bây giờ, tuyên bố về "hình thành không đúng" đặc biệt chỉ phát sinh trong bối cảnh khởi tạo danh sách. Đây là lý do tại sao nếu bạn khởi tạo vector của bạn mà không {}s
, bạn không nhìn thấy cảnh báo rằng:
vec3<T> operator-(const vec3<T> &other) {
// totally OK: implicit conversion from int --> char is allowed here
return vec3<T>(x - other.x, y - other.y, z - other.z);
}
Như để giải quyết vấn đề này - chỉ cần gọi các nhà xây dựng mà không cần list-khởi tạo có lẽ là giải pháp đơn giản nhất. Ngoài ra, bạn có thể tiếp tục sử dụng danh sách-khởi và chỉ template constructor của bạn:
template <typename A, typename B, typename C>
vec3(A xx, B yy, C zz)
: x(xx) // note these all have to be()s and not {}s for the same reason
, y(yy)
, z(yy)
{ }
Hãy nhìn vào các cuộc thảo luận trong này [báo cáo lỗi GCC] (https://gcc.gnu.org/bugzilla/show_bug. cgi? id = 44500), đặc biệt là [câu trả lời của Jonathan Wakely] (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=44500#c3) –
'{}' bắt thu hẹp chuyển đổi (làm cho mã bị hỏng hình thành). '()' không. Hay bạn đang hỏi tại sao nó lại thu hẹp? –
Có, tại sao nó lại thu hẹp? – hidayat