2014-11-19 17 views
5

Nếu tôi có một chút mã như:std :: vòng loại cần thiết khi chức năng không gian tên quá tải tồn tại?

using namespace std; 

namespace myNamespace 
{ 
    vector<float> sqrt(vector<float> v) { return v; } 

    void func() 
    { 
     vector<float> myVec = { 1, 2, 3, 4 }; 
     std::cout << sqrt(myVec)[0] << std::endl; 
     float myFloat = 4.0f; 
     std::cout << sqrt(myFloat) << std::endl; // need to use std::sqrt() 
    } 
} 

thì nó sẽ không biên dịch, trừ khi tôi đã thay đổi dòng đánh dấu để sử dụng std::sqrt. Tại sao? Tôi hiểu rằng nếu tôi cố gắng xác định lại sqrt(float) trong myNamespace thì tôi phải đủ điều kiện với std:: nếu tôi muốn sử dụng phiên bản thư viện chuẩn. Trình biên dịch xuất hiện để cố gắng chuyển đổi myFloat thay vì chỉ sử dụng một hàm trong không gian tên khác (std).

Một cách mà tôi nhận thấy là xác định sqrt(vector<float>) trong không gian tên std nhưng điều đó không hoàn toàn đúng và câu trả lời cho this question đề xuất quá tải trong std là bất hợp pháp. Có lẽ không phải là cách để đi sau đó ...

Làm cách nào để quá tải sqrt (hoặc bất kỳ hàm cmath thư viện chuẩn nào khác). chọn dựa trên các tham số hàm được truyền?

Cảm ơn.

+1

Tuyên bố chức năng của riêng bạn trong 'namespace std' chắc chắn là sai. Bạn * có thể * khai báo nó trong không gian tên chung, vì bạn đã bỏ 'std' trong đó vì một lý do nào đó. Hoặc bạn có thể thêm 'using std :: sqrt;' vào không gian tên của bạn, cùng với 'sqrt' của bạn. Tôi chỉ đủ điều kiện tên đúng. –

+1

Bạn cũng có thể không sử dụng 'sử dụng không gian tên somethingsomething' và luôn luôn sử dụng tiền tố std ::, tránh crap như thế này hoàn toàn. – Cubic

Trả lời

9

Trong C++, name lookup không quan tâm đến các thông số loại , chỉ có tên vấn đề. Khi trình biên dịch tìm kiếm một hàm có tên là sqrt, nó sẽ luôn tìm thấy phiên bản của bạn trước tiên (vì tra cứu bắt đầu với vùng tên kèm theo) và dừng ở đó.

Bạn phải giúp trình biên dịch bằng cách đưa tên từ std:: vào phạm vi với một chỉ thị using trong không gian tên của bạn:

namespace myNamespace 
{ 
    using std::sqrt 
    ... 
} 

Sau đó, độ phân giải quá tải tiêu chuẩn sẽ diễn ra để phân biệt giữa bạn sqrtstd::sqrt, và sẽ chọn đúng chức năng sqrt để gọi.

Để tránh bất kỳ sự mơ hồ, bạn nên luôn luôn đủ điều kiện tên (std::sqrt hay myNamespace::sqrt)


Ghi chú:

  • Như đã chỉ ra bởi đơn giản, Argument Dependent Lookup (ADL) làm std::sqrt sẵn cho tên tra cứu trong trường hợp đầu tiên (kể từ vector là trong std::), nhưng nó không thay đổi vấn đề bạn đang phải đối mặt.

  • Tuyên bố sqrt chức năng của riêng bạn trong std:: là một ý tưởng rất xấu (cấm theo tiêu chuẩn, ngoại trừ mẫu chuyên ngành)

+0

Có cách nào để đưa tất cả các tên :: std vào không gian tên hiện tại không? Một cái gì đó như sử dụng std :: *? – user2746401

+2

Mặc dù vậy, nó quan tâm đến các loại tham số. Trong lần gọi đầu tiên tới 'sqrt', trình biên dịch sẽ tìm thấy cả' myNamespace :: sqrt' và 'std :: sqrt' thông qua ADL (vì' vector' nằm trong 'std'). Nó chỉ chọn 'myNamespace :: sqrt' vì nó phù hợp hơn. – Simple

+0

@ Đơn giản: điểm tốt, ghi chú đã thêm – quantdev

2

Bạn có thể mang lại std::sqrt vào không gian tên của bạn thông qua báo cáo kết quả using std::sqrt; trong myNamespace:

namespace myNamespace 
{ 
    vector<float> sqrt(vector<float> v) { return v; } 
    using std::sqrt; 
    ... 

Sau đó trình biên dịch sẽ chọn thích hợp sqrt trong std::cout << sqrt(myFloat)

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