Hãy xem xét các đặc điểm kỹ thuật của dãy dựa trên vòng lặp for của bắt đầu-expr và cuối expr (N4140 [stmt.ranged]/p1). Với một loạt __range
loại _RangeT
,Mô phỏng cuối hành vi phạm dựa trên vòng lặp for của begin/
bắt đầu-expr và cuối expr được xác định như sau:
- nếu
_RangeT
là một loại mảng, bắt đầu-expr và end-expr là__range
và__range + __bound
, tương ứng, trong đó__bound
là mảng bị ràng buộc. Nếu_RangeT
là một mảng có kích thước không xác định hoặc một mảng loại không đầy đủ, chương trình không đúng định dạng;- nếu
_RangeT
là một loại lớp, các không đủ tiêu chuẩn-id sbegin
vàend
đang nhìn lên trong phạm vi của lớp_RangeT
như thể bằng cách truy cập thành viên lớp tra cứu (3.4.5), và nếu một trong hai (hoặc cả hai) tìm thấy ít nhất một khai báo , bắt đầu-expr và end-expr là__range.begin()
và__range.end()
, tương ứng;- khác, bắt đầu-expr và cuối expr là
begin(__range)
vàend(__range)
, tương ứng, nơibegin
vàend
đang nhìn lên trong các không gian tên kèm theo (3.4.2). [Lưu ý: Thông thường không đủ tiêu chuẩn tra cứu (3.4.1) không được thực hiện. - cuối note]
Có thể để mô phỏng chính xác hành vi này trong C++ bình thường? ví dụ, chúng ta có thể viết một magic_begin
và magic_end
hàm mẫu mà
for(auto&& p : range_init) { /* statements */ }
và
{
auto&& my_range = range_init;
for(auto b = magic_begin(my_range), e = magic_end(my_range); b != e; ++b){
auto&& p = *b;
/* statements */
}
}
luôn có hành vi chính xác giống nhau không?
Non-câu trả lời bao gồm điện thoại đủ điều kiện để std::begin
/std::end
(không xử lý viên đạn thứ ba, trong số những thứ khác) và using std::begin; begin(range);
bởi vì, trong số những thứ khác, đó là mơ hồ nếu ADL cho begin
tìm thấy một tình trạng quá tải đó đều tốt như std::begin
.
Để minh hoạ, trao
namespace foo {
struct A { int begin; };
struct B { using end = int; };
class C { int* begin(); int *end(); }; // inaccessible
struct D { int* begin(int); int* end();};
struct E {};
template<class T> int* begin(T&) { return nullptr; }
template<class T> int* end(T&) { return nullptr; }
}
foo::A a; foo::B b; foo::C c; foo::D d; foo::E e;
Tôi muốn magic_begin(a)
/magic_begin(b)
/magic_begin(c)
/magic_begin(d)
là một lỗi biên dịch, và magic_begin(e)
trở (int*)nullptr
.
Ý bạn là, bạn muốn 'magic_end' là lỗi biên dịch cho' b', phải không? – Columbo
@Columbo Vâng, nếu chúng ta đang theo dõi đặc điểm kỹ thuật dựa trên phạm vi, thì cả hai sẽ là lỗi. Nhưng tôi hài lòng với "ít nhất một trong các' magic_begin' và 'magic_end' dẫn đến lỗi". –
Ồ, xin lỗi! Đã đọc sai dấu đầu dòng thứ hai. – Columbo