số int -> quy tắc chuyển đổi con trỏ


19

Hãy xem xét các mã sau đây.

void f(double p) {}
void f(double* p) {}

int main()
{ f(1-1); return 0; }

MSVC 2017 không biên dịch được điều đó. Nó chỉ ra rằng có một cuộc gọi quá tải mơ hồ, 1-1giống như 0và do đó có thể được chuyển đổi thành double*. Các thủ thuật khác, như 0x0, 0Lhoặc static_cast<int>(0), cũng không hoạt động. Ngay cả việc khai báo a const int Zero = 0và gọi cũng f(Zero)tạo ra lỗi tương tự. Nó chỉ hoạt động đúng nếu Zerokhông const.

Có vẻ như vấn đề tương tự áp dụng cho GCC 5 trở xuống, nhưng không phải GCC 6. Tôi tò mò liệu đây có phải là một phần của tiêu chuẩn C ++, lỗi MSVC đã biết hoặc cài đặt trong trình biên dịch. Google không mang lại kết quả.

Câu trả lời:


18

MSVC coi 1-1là một hằng con trỏ null. Điều này đúng với tiêu chuẩn cho C ++ 03, trong đó tất cả các biểu thức hằng số nguyên có giá trị 0là hằng số con trỏ null, nhưng nó đã được thay đổi để chỉ các số nguyên bằng 0 là hằng số con trỏ null cho C ++ 11 với vấn đề CWG 903 . Đây là một thay đổi đột phá, như bạn có thể thấy trong ví dụ của mình và cũng như được ghi lại trong tiêu chuẩn, xem [diff.cpp03.conv] của tiêu chuẩn C ++ 14 (dự thảo N4140).

MSVC chỉ áp dụng thay đổi này trong chế độ tuân thủ. Vì vậy, mã của bạn sẽ biên dịch với /permissive-cờ, nhưng tôi nghĩ rằng thay đổi chỉ được thực hiện trong MSVC 2019, xem tại đây .

Trong trường hợp của GCC, GCC 5 mặc định ở chế độ C ++ 98, trong khi GCC 6 và sau đó mặc định là chế độ C ++ 14, đó là lý do tại sao sự thay đổi trong hành vi dường như phụ thuộc vào phiên bản GCC.

Nếu bạn gọi fvới hằng số con trỏ null làm đối số, thì cuộc gọi không rõ ràng, bởi vì hằng số con trỏ null có thể được chuyển đổi thành giá trị con trỏ null của bất kỳ loại con trỏ nào và chuyển đổi này có cùng thứ hạng với chuyển đổi của int(hoặc bất kỳ loại tích phân nào) để double.


-1

Trình biên dịch hoạt động chính xác, theo [over.match][conv] , cụ thể hơn là [conv.fpint] và [conv.ptr].

Chuỗi chuyển đổi tiêu chuẩn là [blah blah] Không hoặc một [...] chuyển đổi tích phân trôi nổi, chuyển đổi con trỏ, [...].

Một giá trị của loại số nguyên hoặc loại liệt kê không có phạm vi có thể được chuyển đổi thành giá trị của loại dấu phẩy động. Kết quả là chính xác nếu có thể [blah blah]

Hằng số con trỏ null là một số nguyên có giá trị bằng 0 hoặc [...]. Một hằng con trỏ null có thể được chuyển đổi thành một loại con trỏ; kết quả là giá trị con trỏ null của loại đó [blah blah]

Bây giờ, độ phân giải quá tải là chọn kết quả phù hợp nhất trong số tất cả các chức năng của ứng viên (mà, như một tính năng thú vị, thậm chí không thể truy cập được tại vị trí cuộc gọi!). Kết quả phù hợp nhất là kết quả có tham số chính xác hoặc, thay vào đó, ít chuyển đổi nhất có thể. Không hoặc một chuyển đổi tiêu chuẩn có thể xảy ra (... cho mọi tham số) và không "tốt hơn" so với một tham số.

(1-1)là một số nguyên có giá trị 0.

Bạn có thể chuyển đổi các literal zero số nguyên để mỗi một trong hai doublehoặc double*(hoặc nullptr_t), với chính xác một chuyển đổi. Vì vậy, giả sử rằng nhiều hơn một trong số các hàm này được khai báo (như trường hợp trong ví dụ), tồn tại nhiều hơn một ứng cử viên và tất cả các ứng cử viên đều tốt như nhau, không tồn tại kết quả phù hợp nhất. Đó là mơ hồ, và trình biên dịch là đúng về khiếu nại.


1
Làm thế nào là 1-1một số nguyên ? Nó là một biểu thức chứa hai chữ nguyên có giá trị 1-toán tử.
quả óc chó

@walnut: Có lẽ bạn đề cập đến từ ngữ khó hiểu "chuỗi các chữ số nhị phân, số bát phân, chữ số hoặc chữ số thập lục phân" . Đó là một từ ngữ rất không may mắn cho một cái gì đó khá "rõ ràng", trong đó gợi ý một cái gì đó không phải là trường hợp (tức là loại trừ ký tự trừ). Chỉ với "chữ số" và theo phương pháp sư phạm theo định nghĩa của "chữ số" (một trong 0 ... 9), không thể có bất kỳ chữ viết tắt âm nào (chẳng hạn như -1). Tuy nhiên, do loại mặc định được , rõ ràng là cần thiết và nó cũng có thể được chấp nhận (và được chấp nhận rộng rãi).
Damon

1
Tôi đang đề cập đến ngữ pháp cho số nguyên được hiển thị trong liên kết tiêu chuẩn, không phù hợp 1-1. C ++ không có số nguyên âm. -1là một biểu thức được tạo thành từ một 1số nguyên (loại đã ký) và một -toán tử trừ đơn nguyên. Xem thêm phần "Ghi chú" trên cppreference.com .
quả óc chó

Điều chắc chắn là ngữ pháp không có nó, nhưng điều đó không quan trọng. Theo sự cần thiết và theo định nghĩa, C ++ rất nhiều u nghĩa đen , vì trừ khi bạn viết thêm một cách rõ ràng , nghĩa đen của bạn là, theo định nghĩa, được ký. Các loại đã giá trị âm (khoảng 50% giá trị có thể là âm). Thật không may là ngữ pháp (vì một lý do mà tôi không biết) bị hiểu sai theo cách này, và mặc dù về mặt kỹ thuật (theo ngữ pháp) -1 là một nghĩa đen tích cực, bị phủ định, bởi tất cả các phương tiện khác đều là phủ định nghĩa đen Giống như 3 + 4 là một nghĩa đen.
Damon

Nhân tiện - tôi đã thử 0U. Cùng một vấn đề. Những gì tôi đã không cố gắng là một enumgiá trị. Có lẽ một người được đặt tên sẽ thay đổi mọi thứ. Tôi đã kết thúc bằng cách viết một biểu thức dài với decltyperemove_reference.
dùng1334767
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.