2017-07-22 19 views
26

tôi đang tìm kiếm tại generate()generate_n() trong cppreference và đang cố gắng tìm hiểu tại sao generate() đòi hỏi ForwardIterator, trong khi đòi hỏi generate_n()OutputIterator cho phạm vi? (Tôi đã kiểm tra dự thảo làm việc mới nhất của Standard, và đó là yêu cầu tương tự.)Tại sao std :: generate() và std :: generate_n() yêu cầu các trình lặp khác nhau?

Bởi vì, ít nhất là thực hiện khác nhau của họ dường như đòi hỏi các khái niệm iterator giống hệt nhau và OutputIterator có vẻ là đủ:

generate():

template<class ForwardIt, class Generator> 
void generate(ForwardIt first, ForwardIt last, Generator g) 
{ 
    while (first != last) { 
     *first++ = g(); 
    } 
} 

generate_n():

template<class OutputIt, class Size, class Generator> 
OutputIt generate_n(OutputIt first, Size count, Generator g) 
{ 
    for (Size i = 0; i < count; i++) { 
     *first++ = g(); 
    } 
    return first; 
} 

Cùng với câu chuyện std::fill()std::fill_n().

Trả lời

36

ít nhất thực hiện khác nhau của họ dường như đòi hỏi khái niệm iterator giống hệt nhau và OutputIterator có vẻ là đủ

OutputIterator không hỗ trợ bình đẳng/bất bình đẳng so sánh (bao gồm operator!= sử dụng trong việc thực hiện có thể có của generate() bạn thấy) và đảm bảo nhân, trong khi ForwardIterator. Điều đó có nghĩa là không thể sử dụng OutputIterator để đại diện cho một dải ô qua hai trình lặp (ví dụ: [first, last)) được yêu cầu bởi giao diện của generate().

Bình đẳng và bất bình đẳng có thể không được xác định cho các trình vòng lặp đầu ra. Ngay cả khi toán tử == được xác định, x == y không cần ngụ ý ++ x == ++ y.

9

songyuanyao's answer giải thích vấn đề từ quan điểm kỹ thuật. Tôi sẽ cố gắng giải thích không chính thức hơn một chút.

Nhiều thuật toán STL, bao gồm generatefill, được áp dụng cho một số mục. Cách một thuật toán phải có khả năng truy cập các mục đó xác định các yêu cầu cho trình lặp.

Trong trường hợp của bạn, định nghĩa về generate chứa:

... 
while (first != last) { // implies that Iter implements operator!= 
    *first++;    // implies that Iter implements operator++ 

Trong khi yêu cầu thứ hai dường như được thỏa mãn bởi bất kỳ loại iterator (sau khi tất cả, đó là những gì lặp là tất cả về - iterating trên điều :)) , hỗ trợ để so sánh operator!= được cung cấp bởi không phải tất cả các loại trình lặp.

Ví dụ: bạn không thể sử dụng ostream_iterator cho std::generate. Tuy nhiên, bạn có thể, ví dụ:, xuất một số giá trị được tạo cố định vào luồng qua std::generate_n.

Đây là a very artificial example at Coliru. Khi tôi bắt đầu nghĩ về các ứng dụng thực tế, tôi đoán khả năng làm việc với OutputIterators có thể hữu ích cho việc thực hiện một số logic tuần tự hóa.

7

generate()generate_n(), giống như tất cả các thuật toán thư viện chuẩn, hoạt động trên dải , tức là chuỗi các giá trị được truy cập thông qua trình lặp. Để áp dụng một hoạt động cho tất cả các phần tử của một dãy, thuật toán phải biết phạm vi bắt đầu và nơi nó kết thúc. Có hai cách phổ biến để cho nó thông tin đó: bạn có thể chỉ định phạm vi với một trình lặp và chiều dài, và sử dụng một vòng lặp của biểu mẫu while (length-- != 0) { ... ++first; }; hoặc bạn có thể chỉ định phạm vi với một cặp vòng lặp [first, last) và sử dụng một vòng lặp của biểu mẫu while (first != last) { ... ++first; }.

Đối với phiên bản đầu tiên, bạn cần có khả năng tăng trình lặp và, đối với các thuật toán này, hãy viết giá trị thông qua trình lặp. Đó là những sự phù hợp chính của bộ lặp đầu ra đầu ra, và đó là tất cả những gì bạn cần cho generate_n().

Đối với phiên bản thứ hai, bạn cần có khả năng tăng trình lặp và ghi giá trị thông qua trình lặp, giống như phiên bản đầu tiên. Bạn cũng phải có khả năng so sánh hai trình vòng lặp cho sự bình đẳng, và trình lặp đầu ra không hỗ trợ điều đó; bạn phải có ít nhất một thiết bị chuyển tiếp về phía trước. Đó là lý do tại sao generate(), trong đó có một phạm vi được chỉ định bởi một cặp vòng lặp, yêu cầu một trình lặp chuyển tiếp.

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