2009-06-11 59 views
22

Các trình lặp của Python thực hiện trình lặp vòng lặp chain về cơ bản nối một số trình lặp khác nhau để cung cấp mọi thứ từ trình lặp đơn.Các trình lặp vòng lặp cho C++

Có điều gì tương tự trong C++ không? Một cái nhìn nhanh về các thư viện tăng cường đã không tiết lộ một cái gì đó tương tự, đó là khá đáng ngạc nhiên với tôi. Có khó thực hiện chức năng này không?

+0

Tôi tìm thấy điều này: http://echochamber.me/viewtopic.php?f=11&t=19074, thực hiện điều gì đó tương tự, mặc dù không giống như tôi muốn. – ynimous

Trả lời

18

Đến với câu hỏi này trong khi điều tra về một vấn đề tương tự.

Ngay cả khi câu hỏi cũ, bây giờ trong thời điểm C++ 11 và tăng 1.54, việc sử dụng thư viện Boost.Range khá dễ dàng. Nó có một số join-function, có thể kết hợp hai phạm vi thành một dải ô duy nhất. Ở đây bạn có thể phải chịu các hình phạt về hiệu suất, vì khái niệm phạm vi chung thấp nhất (ví dụ: Single Pass Range or Forward Range, v.v.) được sử dụng làm danh mục phạm vi mới và trong khi lặp lại, trình vòng lặp có thể được kiểm tra nếu cần chuyển sang phạm vi mới, nhưng mã của bạn có thể dễ dàng được viết như:

#include <boost/range/join.hpp> 

#include <iostream> 
#include <vector> 
#include <deque> 

int main() 
{ 
    std::deque<int> deq = {0,1,2,3,4}; 
    std::vector<int> vec = {5,6,7,8,9}; 

    for(auto i : boost::join(deq,vec)) 
    std::cout << "i is: " << i << std::endl; 

    return 0; 
} 
+7

Điều này có thể thực hiện mà không tăng cường? –

1

Không có trong thư viện chuẩn. Boost có thể có thứ gì đó.

Nhưng thực sự, một điều như vậy sẽ không đáng kể để thực hiện. Chỉ cần làm cho mình một iterator với một vector của iterators như là một thành viên. Một số mã rất đơn giản cho toán tử ++, và bạn đang ở đó.

+0

Nó sẽ phải là cặp lặp - bạn cần phải biết nơi mà mỗi người dừng lại. –

4

Trong C++, trình lặp thường không có ý nghĩa bên ngoài ngữ cảnh bắt đầu và kết thúc phạm vi. Bản thân trình vòng lặp không biết bắt đầu và kết thúc ở đâu. Vì vậy, để làm một cái gì đó như thế này, bạn thay vì cần phải chuỗi với nhau phạm vi của iterators - phạm vi là một (bắt đầu, kết thúc) cặp lặp.

Hãy xem tài liệu boost::range. Nó có thể cung cấp các công cụ để xây dựng một chuỗi các dãy. Sự khác biệt duy nhất là chúng sẽ phải là cùng loại và trả về cùng một loại trình lặp. Nó có thể tiếp tục có thể làm cho điều này chung chung hơn nữa để kết nối các loại khác nhau của các phạm vi với một cái gì đó giống như any_iterator, nhưng có lẽ không.

2

Tôi đã viết một trước (thực ra, chỉ cần ghép hai cặp vòng lặp lại với nhau). Nó không phải là khó, đặc biệt là nếu bạn sử dụng tăng của iterator_facade.

Tạo trình lặp đầu vào (đó là cách hiệu quả của những gì Python chain làm) là một bước đầu tiên dễ dàng. Việc tìm kiếm danh mục chính xác cho một trình lặp chuỗi kết hợp các loại trình lặp khác nhau được để lại dưới dạng một bài tập cho người đọc ;-).

+0

Chaining ba iterators với nhau là tầm thường bởi iteration: ((A, B), C) – MSalters

0

Không có chức năng nào tồn tại trong việc tăng cường thực hiện điều này, theo hiểu biết tốt nhất của tôi - tôi đã thực hiện tìm kiếm khá rộng rãi. Tôi nghĩ tôi sẽ thực hiện điều này một cách dễ dàng tuần trước, nhưng tôi gặp phải một snag: STL đi kèm với Visual Studio 2008, khi kiểm tra phạm vi được bật, không cho phép so sánh trình lặp từ các vùng chứa khác nhau (nghĩa là, bạn không thể so sánh somevec1.end() với somevec2.end()). Đột nhiên nó trở nên khó khăn hơn để thực hiện điều này và tôi đã không hoàn toàn quyết định về việc làm thế nào để làm điều đó.

Tôi đã viết các trình vòng lặp khác trong quá khứ bằng cách sử dụng iterator_facade và iterator_adapter từ tăng, tốt hơn viết các trình biến đổi 'nguyên' nhưng tôi vẫn thấy viết các trình vòng lặp tùy chỉnh trong C++ khá lộn xộn.

Nếu ai đó có thể đăng một số mã giả về cách thức này có thể được thực hiện/không/so sánh trình lặp từ các vùng chứa khác nhau, tôi sẽ bị ràng buộc nhiều.

+0

Không STL cho phép thực sự. VS2008 chỉ nói với bạn sớm hơn. Nhưng thiết kế nên cho phép chuỗi một trình lặp vector và một trình vòng lặp danh sách, trong trường hợp đó, một so sánh sẽ là một lỗi kiểu. – MSalters

1

Kiểm tra Views Template Library (VTL). Nó có thể không trực tiếp cung cấp 'chuỗi lặp'. Nhưng tôi nghĩ rằng nó có tất cả các công cụ/mẫu cần thiết có sẵn để triển khai 'trình lặp lặp chuỗi' của riêng bạn.


Từ VTL Page:

Một quan điểm là một bộ chuyển đổi container, cung cấp một giao diện container để

  1. bộ phận của dữ liệu hoặc
  2. một sắp xếp lại các dữ liệu hoặc
  3. dữ liệu được chuyển đổi hoặc
  4. sự kết hợp phù hợp của bộ dữ liệu

(các) vùng chứa bên dưới. Vì chính khung nhìn cung cấp giao diện vùng chứa, chúng có thể dễ dàng được kết hợp và xếp chồng lên nhau. Do thủ thuật mẫu, chế độ xem có thể điều chỉnh giao diện của chúng thành (các) vùng chứa bên dưới. Thủ thuật mẫu phức tạp hơn làm cho tính năng mạnh mẽ này trở nên dễ sử dụng.

So với các trình vòng lặp thông minh, các khung nhìn chỉ là các nhà máy lặp thông minh.

2

Những gì bạn đang tìm kiếm cơ bản là một trình lặp mặt tiền tóm tắt đi ngang qua một vài chuỗi.

Vì bạn đến từ nền python, tôi cho rằng bạn quan tâm nhiều hơn đến tính linh hoạt thay vì tốc độ. Bởi tính linh hoạt, tôi có nghĩa là khả năng chuỗi lặp lại thông qua các loại trình tự khác nhau với nhau (vectơ, mảng, danh sách liên kết, tập hợp ...) và theo tốc độ, tôi chỉ phân bổ bộ nhớ từ ngăn xếp.

Nếu đây là trường hợp sau đó bạn có thể muốn nhìn vào any_iterator từ phòng thí nghiệm adobe: http://stlab.adobe.com/classadobe_1_1any__iterator.html

iterator này sẽ cung cấp cho bạn khả năng lặp thông qua bất kỳ loại chuỗi khi chạy. Để chuỗi bạn sẽ có một vectơ (hoặc mảng) của bất kỳ bộ ba thứ ba nào đó, nghĩa là, ba any_iterators cho mỗi dải bạn kết hợp với nhau (bạn cần ba để lặp lại tiến hoặc lùi, nếu bạn chỉ muốn lặp lại hai thì đủ).

Hãy nói rằng bạn muốn chuỗi lặp thông qua một chuỗi các số nguyên:

(psuedo-c chưa được kiểm tra ++ code)

typedef adobe :: any_iterator AnyIntIter;

struct AnyRange { AnyIntIter bắt đầu; curr AnyIntIter; Kết thúc AnyIntIter; };

Bạn có thể xác định phạm vi như:

int int_array [] = {1, 2, 3, 4}; Trình tự AnyRange_0 = {int_array, int_array, int_array + ARRAYSIZE (int_array)};

Lớp RangeIterator của bạn sau đó sẽ có một std :: vector.

<code> 
class RangeIterator { 
public: 
    RangeIterator() : curr_range_index(0) {} 

    template <typename Container> 
    void AddAnyRange(Container& c) { 
    AnyRange any_range = { c.begin(), c.begin(), c.end() }; 
    ranges.push_back(any_range); 
    } 

    // Here's what the operator++() looks like, everything else omitted. 
    int operator++() { 

    while (true) { 
     if (curr_range_index > ranges.size()) { 
     assert(false, "iterated too far"); 
     return 0; 
     } 
     AnyRange* any_range = ranges[curr_range_index]; 
     if (curr_range->curr != curr_range->end()) { 
     ++(curr_range->curr); 
     return *(curr_range->curr); 
     } 
     ++curr_range_index;  
    } 
    } 


private: 
    std::vector<AnyRange> ranges; 
    int curr_range_index; 
}; 
</code> 

Tôi muốn lưu ý rằng giải pháp này rất chậm. Cách tiếp cận tốt hơn, C++ giống như là chỉ lưu trữ tất cả các con trỏ tới các đối tượng mà bạn muốn vận hành và lặp lại thông qua đó. Ngoài ra, bạn có thể áp dụng một functor hoặc một khách truy cập vào phạm vi của bạn.

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