2013-10-28 13 views
5

Xét đoạn mã sau:Tại sao hàm merge() toàn cục xung đột với std :: merge()?

#include <vector> 
#include <algorithm> 

template <typename Input1, typename Input2, typename Output> 
void merge(Input1 begin1, Input1 end1, Input2 begin2, Input2 end2, Output out) 
{ 
} 

int main() 
{ 
    std::vector<int> a = {1, 2}; 
    int b[] = {3, 4}; 
    int c[4]; 

    merge(a.begin(), a.end(), b, b + 2, c); 
} 

sản lượng Biên soạn:

$ clang++ -std=c++11 -stdlib=libc++ merge.cpp 
merge.cpp:15:5: error: call to 'merge' is ambiguous 
    merge(a.begin(), a.end(), b, b + 2, c); 
    ^~~~~ 
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/algorithm:4056:1: note: 
     candidate function [with _InputIterator1 = std::__1::__wrap_iter<int *>, 
     _InputIterator2 = int *, _OutputIterator = int *] 
merge(_InputIterator1 __first1, _InputIterator1 __last1, 
^ 
merge.cpp:5:6: note: candidate function [with Input1 = std::__1::__wrap_iter<int 
     *>, Input2 = int *, Output = int *] 
void merge(Input1 begin1, Input1 end1, Input2 begin2, Input2 end2, Output out) 
    ^
1 error generated. 

Compiler phiên bản:

$ clang++ --version 
Apple LLVM version 5.0 (clang-500.2.78) (based on LLVM 3.3svn) 
Target: x86_64-apple-darwin13.0.0 
Thread model: posix 

Tại sao cuộc gọi đến merge mơ hồ? Nó không chắc chắn nếu tôi có nghĩa là ::merge() hoặc std::merge(), mặc dù rõ ràng (?) Nó phải là ::merge() vì tôi không chỉ định bất kỳ chỉ thị using nào. Hàm merge của tôi nằm trong không gian tên chung, mà tôi nghĩ sẽ không xung đột với bất kỳ thứ gì trong không gian tên std (vì đó là điểm chính của không gian tên, đúng không?). Nếu tôi thay đổi a thành một mảng int giống như những người khác, nó biên dịch mà không có bất kỳ sự mơ hồ nào. Ngoài ra, thêm dấu hai chấm và gọi số ::merge() hoạt động tốt.

Vì vậy, câu hỏi của tôi là: Đây có phải là một lỗi trong Clang, hay tôi có một sự hiểu lầm về không gian tên? Tại sao cuộc gọi của tôi đến merge() dẫn đến sự mơ hồ khi hai chức năng không nằm trong cùng một không gian tên và tôi không hiển thị std::merge() với bất kỳ chỉ thị using nào?

+0

Và đối với những người tự hỏi tại sao tôi làm điều này, tôi chỉ thực hành triển khai sắp xếp hợp nhất. – Cornstalks

Trả lời

5

Sự cố là std::vector<T>::iterator có thể là loại lớp (trong trường hợp của bạn, loại lớp): trong quá trình phân giải quá tải, trình biên dịch tìm tất cả các khai báo hiển thị của hàm. Để kết thúc này, nó đi tìm trong không gian tên có thể liên kết với các đối số của nó (điều này được gọi là đối số phụ thuộc tra cứu). Loại std::vector<T>::iterator được định nghĩa trong không gian tên std (hoặc không gian tên được lồng trong) và, do đó, chức năng từ không gian tên std được xem xét cho các độ phân giải quá tải. Kể từ std::merge()merge() cả hai đều phù hợp như nhau, có một sự mơ hồ.

Cách dễ nhất để tránh sự cố là sử dụng tên khác cho mẫu chức năng. Ẩn không gian tên liên quan là có thể nhưng không dễ dàng: các không gian tên được kết hợp được lấy từ vị trí mà một lớp hoặc một mẫu lớp được định nghĩa cũng như từ các lớp cơ sở và các đối số mẫu của nó. Do đó, việc tạo một mẫu trình bao bọc cho bất kỳ loại trình vòng lặp nào sẽ không đủ vì nó vẫn liên kết không gian tên ban đầu với các kiểu. Bạn có thể cố gắng làm cho mẫu hàm của bạn phù hợp hơn nhưng cho rằng nó có nghĩa là giống như thuật toán chuẩn, điều này không hoàn toàn khả thi.

2

Đó là do đối số phụ thuộc tra cứu (http://en.cppreference.com/w/cpp/language/adl) của một trình lặp từ không gian tên std.

bạn có thể viết ::merge để chỉ có chức năng của bạn, nhưng tôi chỉ muốn sử dụng một tên khác.