2015-09-20 13 views
6

Đây là một phần mở rộng cho câu hỏi này từ năm 2011: Range-based for loops and ADLPhạm vi-Based Đối Loop và ADL

Sử dụng Visual Studio 2015, tôi không thể đưa ra một loạt dựa trên vòng lặp for cho một Argument chứa tùy chỉnh sử dụng Dependent Lookup (ADL).

Tôi đã thực hiện một trường hợp thử nghiệm rất đơn giản dưới đây với một container tùy chỉnh:

#include <vector> 

namespace Foo 
{ 
    template <typename T> 
    class Container 
    { 
    public: 

     std::vector<T> values; 
    }; 
} 

template <typename T> 
typename std::vector<T>::iterator begin(Foo::Container<T>& foo) 
{ 
    return foo.values.begin(); 
} 

template <typename T> 
typename std::vector<T>::iterator end(Foo::Container<T>& foo) 
{ 
    return foo.values.end(); 
} 

Sử dụng thùng chứa này và ADL, các thử nghiệm sau biên dịch hoàn toàn tốt đẹp:

int main(int argc, char* argv[]) 
{ 
    Foo::Container<int> values; 

    for (auto it = begin(values); it != end(values); ++it) 
    { 
     ... 
    } 

    return 0; 
} 

như nó phải. Tôi không chắc liệu ADL có được sử dụng ở đây hay không, nhưng không quan tâm, nó có ý nghĩa. Từ MSDN documentation, ta có:

Hãy ghi nhớ những sự thật về phạm vi có trụ sở tại: mảng

  • Tự động nhận ra.

  • Nhận dạng các vùng chứa có .begin() và .end().

  • Sử dụng tra cứu phụ thuộc vào đối số bắt đầu() và kết thúc() cho bất kỳ mục đích nào khác.

Từ những gì tôi hiểu của ADL, và các tài liệu trên, sau đây cũng nên biên dịch:

int main(int argc, char* argv[]) 
{ 
    Foo::Container<int> values; 

    for (auto value : values) 
    { 
     ... 
    } 

    return 0; 
} 

Nhưng nó không. Thay vào đó, tôi nhận được các lỗi sau:

error C3312: no callable 'begin' function found for type 'Foo::Container<int>' 
error C3312: no callable 'end' function found for type 'Foo::Container<int>' 

Vậy điều gì đang xảy ra ở đây? Là giải thích của tôi về ADL không chính xác, hoặc là một lỗi với MSVC 14.0 Compiler?

+1

IINM 'begin()' và 'end()' phải ở trong 'Foo'. – Quentin

+0

Điều này không phụ thuộc vào ADL vì 'begin' và' end' không nằm trong vùng tên 'Foo', nhưng có vẻ như nó hoạt động tốt trong gcc: http://coliru.stacked-crooked.com/a/12047609140d05a9. Nếu bạn thay đổi 'begin' và' end' để thay thế 'const' ref, nó có hoạt động trên MSVC không? – rici

+0

@rici, Không, không. Nó làm cho tôi tự hỏi tại sao nó hoạt động trong GCC mặc dù câu trả lời của Pavlo là đúng. Trình biên dịch nào là đúng?:) – Zeenobit

Trả lời

7

Bạn phải đặt cả hai beginend vào không gian tên Foo để ADL hoạt động. Điều này là do ADL sẽ xem xét các không gian tên của các đối số tương ứng với các định nghĩa tìm kiếm của beginend.

namespace Foo 
{ 
    template <typename T> 
    class Container 
    { 
    public: 

     std::vector<T> values; 
    }; 

    template <typename T> 
    typename std::vector<T>::iterator begin(Foo::Container<T>& foo) 
    { 
     return foo.values.begin(); 
    } 

    template <typename T> 
    typename std::vector<T>::iterator end(Foo::Container<T>& foo) 
    { 
     return foo.values.end(); 
    } 
} 

UPD: Lý do tại sao beginend từ namespace toàn cục không được coi là do các tiêu chuẩn được cập nhật nói rằng beginend đang nhìn lên trong không gian tên có liên quan nhưng thường unquali tra cứu fi ed không được thực hiện. Đây là hậu quả của sửa lỗi trong tiêu chuẩn (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1442).

+0

Nó cũng hoạt động tốt với 'bắt đầu' và' cuối' được định nghĩa trong không gian tên chung. Tại sao không? – rici

+0

@rici điều này là do tra cứu không đủ tiêu chuẩn bình thường (tra cứu trong không gian tên chung) không được thực hiện theo tiêu chuẩn cập nhật: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1442 –

+0

@ PavloMur Cảm ơn bạn đã làm rõ. – Zeenobit