2012-01-07 30 views
31

Khi biên dịchTại sao nó mơ hồ để gọi ambig bị quá tải (long) và ambig (unsigned long) với một số nguyên theo nghĩa đen?

void ambig( signed long) { } 
void ambig(unsigned long) { } 

int main(void) { ambig(-1); return 0; } 

tôi nhận được

error C2668: 'ambig' : ambiguous call to overloaded function 
    could be 'void ambig(unsigned long)' 
    or 'void ambig(long)' 
while trying to match the argument list '(int)' 

Tôi biết tôi có thể 'sửa chữa' nó bằng cách nói -1L thay vì -1, nhưng tại sao/cách chính xác được này coi mơ hồ ở nơi đầu tiên?

Trả lời

33

Bạn đang chuyển một int vào chức năng quá tải này.

Mặc dù trực giác của con người nói rằng ambig(signed long) nên được ưa thích vì đầu vào của bạn là số nguyên âm (không thể được biểu diễn như vậy bởi một unsigned long), hai chuyển đổi trên thực tế tương đương trong "ưu tiên" trong C++.

Đó là, việc chuyển đổi intunsigned long được coi là chỉ có giá trị như intsigned long, và không được ưa thích để người kia.

Mặt khác, nếu tham số của bạn đã là một long chứ không phải là một int, sau đó là một so khớp chính xác-signed long, không có chuyển đổi cần thiết. This avoids the ambiguity.

void ambig( signed long) { } 
void ambig(unsigned long) { } 

int main(void) { ambig(static_cast<long>(-1)); return 0; } 

"Chỉ một trong những điều đó".


[C++11: 4.13/1]: ("rank chuyển đổi Integer")

Mỗi kiểu dữ liệu integer đã rank chuyển đổi số nguyên quy định như sau:

  • [..]
  • Xếp hạng của loại số nguyên đã ký phải lớn hơn xếp hạng của bất kỳ loại số nguyên nào có dấu có kích thước nhỏ hơn.
  • Xếp hạng của long long int sẽ lớn hơn cấp bậc long int, mà sẽ lớn hơn cấp bậc int, mà phải lớn hơn cấp bậc short int, mà phải lớn hơn cấp bậc ký char.
  • Thứ hạng của bất kỳ loại số nguyên không dấu nào sẽ bằng với thứ hạng của loại số nguyên đã ký tương ứng.
  • [..]

[Lưu ý: Xếp hạng chuyển đổi số nguyên được sử dụng trong định nghĩa của các chương trình khuyến mãi không thể thiếu (4.5) và chuyển đổi số học thông thường (Điều 5). —thêm ghi chú]

Độ phân giải quá tải phức tạp và được xác định trong [C++11: 13.3]; Tôi không thể mang bạn bằng cách trích dẫn phần lớn nó ở đây.

Dưới đây là một điểm nhấn, mặc dù:

[C++11: 13.3.3.1/8]: Nếu không chuyển đổi được yêu cầu để phù hợp với một cuộc tranh cãi với một loại tham số, trình tự chuyển đổi ngầm là trình tự chuyển đổi tiêu chuẩn bao gồm việc chuyển đổi danh tính (13.3.3.1. 1).

[C++11: 13.3.3.1/9]: Nếu không có chuỗi chuyển đổi nào có thể được tìm thấy để chuyển đổi một đối số thành loại thông số hoặc chuyển đổi không đúng định dạng, chuỗi chuyển đổi ẩn không thể được tạo thành.

[C++11: 13.3.3.1/10]: Nếu một vài chuỗi chuyển đổi khác nhau tồn tại mà mỗi chuyển đổi đối số cho loại tham số, chuỗi chuyển đổi ngầm được kết hợp với tham số được xác định là chuỗi chuyển đổi duy nhất được chỉ định chuỗi chuyển đổi không rõ ràng. Với mục đích xếp thứ tự chuyển đổi ngầm như được mô tả trong 13.3.3.2, chuỗi chuyển đổi mơ hồ được coi là chuỗi do người dùng xác định, không thể phân biệt được với bất kỳ chuỗi chuyển đổi được người dùng xác định11 nào khác. Nếu một hàm sử dụng chuỗi chuyển đổi không rõ ràng được chọn là hàm khả thi tốt nhất, cuộc gọi sẽ bị hỏng do việc chuyển đổi một trong các đối số trong cuộc gọi không rõ ràng.

  • /10 là trường hợp bạn đang gặp phải; /8 là trường hợp bạn sử dụng với đối số long.
+2

Đợi, nhưng 'int' →' long' luôn là một chuyển đổi không mất mát. 'int' →' unsigned long' mất một nửa thời gian. Làm thế nào/tại sao họ cùng một thứ hạng ?! – Mehrdad

+10

Chỉ cần tò mò: bất kỳ lý do nào không sử dụng chỉ '-1L' thay vì dàn diễn viên đó? – Mat

+0

@Mat: Không, không. –

3

-1 thuộc loại int. Và int có thể được chuyển đổi hoàn toàn thành signed long hoặc unsigned long.

8

Hằng số -1 có loại int. Vì vậy, bạn đang gọi số ambig với một đối số là int. ambig không có quá tải chấp nhận int, vì vậy, chúng tôi sẽ phải xem xét các chuyển đổi tiềm ẩn mà chúng tôi có thể thực hiện. An int có thể được chuyển đổi hoàn toàn thành long hoặc unsigned long (trong số những thứ khác), cả hai đều là đối số hợp lệ cho ambig. Vì vậy, trình biên dịch không biết chuyển đổi để chọn và bạn cần phải đúc bằng tay (hoặc sử dụng một hằng số dài (-1l) thay vì một hằng số int để bắt đầu với).

Thực tế là -1 là số âm không ảnh hưởng đến nó bởi vì trình biên dịch không xem xét giá trị đối số, chỉ loại của nó.

Các vấn đề liên quan