2011-06-23 51 views
7

Mã sau được biên dịch trên g ++ 4.1.2 và g ++ 4.4.4. Cả hai đều cho kết quả ghi nhận trong các ý kiến.Gọi một hàm có con trỏ không const sẽ chuyển thành hàm mẫu trên một hàm lấy con trỏ tới const

int f(const int * a) 
{ 
    return 0; 
} 

template<typename A> 
int f(A a) 
{ 
    return 1; 
} 

int main() 
{ 
    int x; 
    // return f(&x); // returns 1 
    return f((const int *)&x); // returns 0 
} 

Nó xuất hiện để đun sôi xuống đến một tiếng gọi của f(int *) quyết tâm f<int *>(int *) thay vì dự kiến ​​f(const int *). Tôi thấy điều này gây sốc và hoàn toàn không trực quan.

Đây có phải là lỗi trong g ++, góc tối của C++ hay hiển nhiên vì một lý do nào đó tôi bị thiếu? Nếu nó không phải là một lỗi, lý thuyết hay logic đằng sau nó là gì? Có bất kỳ thực hành an toàn nào về vấn đề này không?

+0

'f (int)' và 'f (const int)' là các nguyên mẫu giống hệt như trình biên dịch ANSI C++ có liên quan – sehe

+1

Đúng, nhưng 'f (int *)' không giống với 'f (const int *)/f (int const *) ' – Roland

+0

Có lẽ. Liên kết: http://stackoverflow.com/questions/2121525/const-pointers-in-overload-resolution/2121616#2121616 – sehe

Trả lời

4

Vâng, tại sao bạn gọi phiên bản const của hàm "mong đợi" trong trường hợp gọi f(&x)?

Loại đối số là int *, như bạn đã biết. Vì vậy, phiên bản f(int *) của hàm là kết quả phù hợp hơn phiên bản f(const int *), vì trong loại đối số trước khớp với chính xác. Trình biên dịch nhìn thấy cơ hội để tạo ra f(int *) từ mẫu và phải mất cơ hội đó. Đó chỉ là cách nó hoạt động trong C++.

Trong trường hợp phiên bản mẫu tốt như phiên bản mẫu, mẫu không phải mẫu thường thắng. Nhưng trong trường hợp này, khi phiên bản mẫu rõ ràng là tốt hơn, phiên bản mẫu sẽ thắng.

Dường như bạn mong đợi trình biên dịch chọn phiên bản không phải mẫu của hàm. Tại sao?

+0

Tôi hy vọng nó sẽ giành chiến thắng do một chuyển đổi const tầm thường và tiềm ẩn. Nó chỉ có vẻ lành mạnh với tôi rằng const nâng cấp một loại con trỏ sẽ luôn luôn xảy ra trước khi xem xét các mẫu. Có lẽ có một ví dụ là tại sao đó không phải là một ý tưởng hay. – Roland

+4

@Roland: Không chuyển đổi> chuyển đổi tầm thường trong độ phân giải quá tải. – ildjarn

+0

@Roland: hãy tưởng tượng rằng bạn có hai cách để thực hiện một thao tác. Nó phá hoại (đối với lập luận của nó). Trong phiên bản 'const', do đó bạn cần thực hiện một bản sao của đối số đầu tiên, điều này rõ ràng là kém hiệu quả hơn. Ví dụ: 'T && toán tử + (T &&, T const &)' hiệu quả hơn 'toán tử T + (T const &, T const &)'. –

8

Đối với mẫu được tạo ra f<int *> không cần chuyển đổi (int * ->const int *), vì vậy nó phù hợp hơn - thực tế, đó là kết hợp chính xác, sẽ chỉ bị mất so với đối sánh chính xác không được tạo khuôn mẫu. cuộc gọi thứ hai.

Giải thích đầy đủ về các quy tắc "phù hợp tốt hơn" có sẵn tại §13.3.3 của tiêu chuẩn C++.

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