Tại sao phạm vi không thể được sử dụng cho chức năng thư viện ống?


10

Jonathan Boccara (tác giả của Fluent C ++ ) đã viết một thư viện có tên là pipe .

"Đường ống" này, trang chính của kho lưu trữ nói, không giống như việc sử dụng các phạm vi, mặc dù nó trông giống nhau: Nó không dựa trên sự lười biếng kéo, mà là háo hức đẩy. Nhưng nó đã tuyên bố rằng người ta không thể sử dụng thư viện phạm vi để thực hiện các hoạt động 'ống' khác nhau. Ví dụ:

  • giải nén - Lấy đầu vào có khóa - về cơ bản là một loạt k-tuples - và tạo ra k đầu ra độc lập, riêng biệt.
  • ngã ba - Tạo nhiều bản sao (độc lập) của một container / phạm vi.

Tôi không hiểu tại sao, về nguyên tắc, đó là trường hợp. (Tất nhiên ngoại trừ các phạm vi mà bạn không thể nhận được vòng lặp kết thúc / sentinel.)

Câu trả lời:


7

Những gì đang được thảo luận về cơ bản là sự khác biệt giữa phương pháp xử lý dựa trên đẩy và phương pháp xử lý dựa trên kéo. Trong một hệ thống đẩy như thư viện ống này, bạn thiết lập một chuỗi xử lý và mỗi bước xử lý sẽ đẩy dữ liệu của nó trực tiếp vào kế tiếp. Trong một hệ thống kéo như các phạm vi, bạn thiết lập một biểu diễn dữ liệu mà bạn có thể truy cập và sửa đổi khi cần. Việc xử lý không tự xảy ra; nó chỉ xảy ra khi ai đó cố gắng tiêu thụ phạm vi.

Các hoạt động unzipforkcả hai hoạt động một-nhiều: chúng lấy một đầu vào duy nhất và ánh xạ nó tới nhiều hoạt động xử lý.

Là một hệ thống đẩy, thư viện ống có thể xử lý các hoạt động một-nhiều do cấu trúc API của nó. Một hoạt động được đại diện bởi một cuộc gọi chức năng; đầu vào được ngụ ý bởi điểm sử dụng (sử dụng >>=hoặc chuyển nó tới bộ xử lý). Các tham số của hàm xác định đầu ra của nó (bỏ qua các tham số có nghĩa là cho chính bộ xử lý). Và vì các hàm C ++ có thể có số lượng tham số tùy ý, nên một hoạt động ánh xạ một-nhiều tự nhiên rơi ra. Bạn chỉ cần cung cấp bộ xử lý thích hợp cho các đầu ra khác nhau.

Là một hệ thống kéo, phạm vi dựa trên các giá trị trả về. C ++ không có cơ chế ngôn ngữ để trả về nhiều giá trị, vì vậy điều tốt nhất chúng ta có thể làm là trả về một "giá trị" đại diện cho nhiều giá trị.

Tuy nhiên, chuỗi bộ điều hợp phạm vi cuối cùng dựa trên các đầu vào là phạm vi . Và một "giá trị" đại diện cho nhiều giá trị " tự nó không phải là một phạm vi. Nó có thể chứa phạm vi, nhưng điều đó không làm cho nó một phạm vi.

Vì vậy, bây giờ bạn phải thực hiện loại "không phải là một phạm vi" rất chắc chắn này và làm cho tất cả các bộ điều hợp phạm vi của bạn hoạt động với nó. Áp dụng bộ điều hợp phạm vi phải phát hoạt động đó qua các loại, tạo ra một hoạt động nhiều-nhiều. Làm điều đó không dễ dàng.

Nhưng quan trọng hơn ... đó có lẽ không phải là điều bạn muốn . Nếu bạn forklà một phạm vi, thì bạn gần như chắc chắn muốn thực hiện xử lý khác nhau trên các phạm vi được nhân rộng. Và điều đó hoàn toàn tắt bất kỳ cơ hội sử dụng các |hoạt động để làm điều đó. Bạn sẽ phải xây dựng các cách để áp dụng bộ điều hợp cho các phần cụ thể của các bộ dữ liệu này. Và những cách đó đang ngày càng giống như một bộ xử lý dựa trên đẩy.

Vào cuối ngày, một hệ thống kiểu kéo chỉ có một đầu ra ở mỗi cấp. Đó chỉ là một phần của khái niệm cốt lõi của một API như vậy: mỗi bước xử lý tạo ra một phạm vi. Điều này có lợi thế của nó (lười xử lý) nhưng đại diện cho các hoạt động một-nhiều là một trong những lĩnh vực yếu của nó.

Phạm vi chắc chắn có thể có một unzipchức năng ( forkthực sự chỉ là sao chép phạm vi). Nhưng nó sẽ không phải là một |bộ chuyển đổi phong cách; nó sẽ là một hàm lấy một phạm vi trên một số loại có thể phân tách và trả về một bộ phạm vi. Nếu bạn muốn xử lý nhiều hơn với chúng, thì bạn sẽ cần lưu trữ bộ dữ liệu trong một giá trị, truy cập các phần tử riêng lẻ và sử dụng chúng khi bạn thấy phù hợp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.