Các danh mục trình lặp của C ++ có cấm viết bộ điều hợp lặp UTF-8 không?


8

Tôi đã làm việc trên bộ điều hợp lặp UTF-8. Theo đó, ý tôi là một bộ chuyển đổi biến một trình vòng lặp thành một charhoặc unsigned chartrình tự thành một trình vòng lặp thành một char32_ttrình tự. Công việc của tôi ở đây được lấy cảm hứng từ trình vòng lặp này mà tôi tìm thấy trên mạng .

Tuy nhiên, khi tôi xem qua tiêu chuẩn khi tôi bắt đầu thực hiện, tôi đã nhận ra rằng: dường như không thể thực hiện một bộ chuyển đổi như vậy trong khi vẫn tuân thủ các yêu cầu mà C ++ đặt trên các trình vòng lặp.

Ví dụ: bạn có thể tạo một trình lặp UTF-8 thỏa mãn các yêu cầu của InputIterator không? Có, nhưng chỉ chừng nào trình lặp mà bạn được cung cấp không phải là Trình nhập liệu. Tại sao?

Bởi vì InputIterator yêu cầu khả năng hủy đăng ký cùng một trình vòng lặp nhiều lần. Bạn cũng có thể hủy đăng ký nhiều bản sao của trình vòng lặp đó, miễn là tất cả chúng đều so sánh bằng nhau.

Tất nhiên, việc hủy bỏ hội thảo một bộ điều hợp lặp UTF-8 đòi hỏi cả việc hủy bỏ hội nghị và có khả năng tăng trình lặp cơ sở. Và nếu iterator đó là InputIterator, thì bạn không thể lấy lại giá trị ban đầu sau khi bạn tăng nó. Và thực tế là các bản sao phải hoạt động có nghĩa là bạn không thể lưu trữ cục bộ một char32_tgiá trị đại diện cho giá trị được giải mã trước đó. Bạn có thể đã làm điều này:

auto it = ...
auto it2 = it; //Copies an empty `char32_t`.
*it;           //Accesses base iterator, storing `it.ch`.
*it;           //Doesn't access the base iterator; simply returns `it.ch`.
*it2;          //Cannot access `it.ch`, so must access base iterator.

OK, tốt, vì vậy bạn không thể sử dụng InputIterators. Nhưng còn ForwardIterator thì sao? Có thể tạo bộ điều hợp ForwardIterator có thể điều chỉnh ForwardIterators qua chuỗi ký tự UTF-8 không?

Đó cũng là vấn đề, bởi vì hoạt động *itđược yêu cầu để sản xuất value_type&hoặc const value_type&. InputIterators có thể phun ra bất cứ thứ gì có thể chuyển đổi thành value_type, nhưng a ForwardIteratorbắt buộc phải cung cấp một tham chiếu thực tế [Forward.iterators] /1.3:

if Xlà một iterator có thể thay đổi, referencelà một tham chiếu đến T; if Xlà một iterator không đổi, referencelà một tham chiếu đếnconst T

Việc truy vấn duy nhất ở đây là cho mọi trình vòng lặp như vậy mang theo một char32_t, chỉ tồn tại để cung cấp lưu trữ cho tham chiếu đó. Và thậm chí sau đó, giá trị đó sẽ phải được cập nhật mỗi khi đối tượng lặp được tăng lên và hủy đăng ký. Điều này vô hiệu hóa tham chiếu cũ và tiêu chuẩn không cho phép rõ ràng rằng (việc vô hiệu chỉ có thể xảy ra khi một trình vòng lặp bị hủy hoặc nếu container nói như vậy).

Mã đã nói ở trên mà tôi tìm thấy trực tuyến không hợp lệ do điều này, vì nó trả về một uint32_t(viết trước C ++ 11) theo giá trị chứ không phải là một tham chiếu thích hợp.

Có bất kỳ truy đòi ở đây? Tôi đã bỏ qua một cái gì đó trong tiêu chuẩn, hoặc một số kỹ thuật thực hiện mà tôi có thể sử dụng để bỏ qua những vấn đề này? Hoặc điều này chỉ đơn giản là không thể với từ ngữ hiện tại của tiêu chuẩn?

Lưu ý: điều kỳ lạ là dường như có thể viết một Bộ tạo đầu ra phù hợp cho chuyển đổi UTF-8. Đó là, một kiểu lấy char32_tvà ghi UTF-8 vào một charhoặc unsigned charBộ tạo đầu ra.


3
Người ta biết rằng từ ngữ của từ ForwardIteratornày không phù hợp với bất kỳ loại trình vòng lặp proxy nào , chẳng hạn như những từ vector<bool>có thể thực hiện được . Có một bài báo nổi tiếng được viết vào năm 1999 bởi Herb Sutter đã giải thích lý do tại sao quyết tâm đó được đưa ra. Trong thời hiện đại, có một xu hướng suy nghĩ lại về vấn đề này. Tôi tìm thấy một bài được viết bởi Eric Niebler . Có thể có nhiều hơn; thậm chí có thể có một số được viết bởi chính Herb Sutter, trong một số đề xuất C ++.
rwong

Với InputIterator, bạn có thể đọc bộ đệm trước khi hủy bỏ trình duyệt lặp không?
dùng253751

@immibis: Ừm, đọc cache gì? Đọc từ trình vòng lặp đầu vào trước khi người dùng thực sự hủy đăng ký, điều đó có thể khiến tôi truy cập vào các trình vòng lặp không hợp lệ, vì trình vòng lặp không nhất thiết phải biết nơi kết thúc của phạm vi. Vì vậy, nếu bạn tăng một trình vòng lặp, điều đó không có nghĩa là bạn nên chấp nhận nó. Ngoài ra, hãy nhớ điểm tôi đã thực hiện khi sao chép InputIterators: Nếu bạn bỏ qua hai bản sao của cùng một trình lặp đầu vào, bạn phải có cùng giá trị.
Nicol Bolas

Câu trả lời:


2

Tôi nghĩ rằng câu trả lời ngắn gọn là có. Một bộ điều hợp trình lặp giải mã UTF-8 (và nói chung hơn, có khả năng yêu cầu nhiều mục đầu vào để tạo ra một mục đầu ra duy nhất) phải được đặt trên đầu của trình lặp mà mô hình (ít nhất là) Trình điều khiển hai chiều.

Lưu ý rằng điều này giả sử bạn chỉ muốn một trình lặp không đổi (nghĩa là bạn chỉ đọc UTF-8 từ đầu vào, không ghi UTF-8 vào bộ sưu tập bên dưới). Nếu bạn muốn hỗ trợ viết, mọi thứ trở nên tồi tệ hơn rất nhiều - việc thay đổi từ giá trị này sang giá trị khác ở cấp UTF-32 có thể dễ dàng tạo ra mã hóa UTF-8 có kích thước khác nhau, vì vậy bạn cần phải chuẩn bị để chèn / xóa các mục ở giữa bộ sưu tập cơ bản nếu bạn định hỗ trợ viết.

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.