Mục đích của C ++ 20 std :: common_Vference là gì?


Câu trả lời:


46

common_reference xuất phát từ những nỗ lực của tôi để đưa ra khái niệm về các trình lặp của STL có khả năng hỗ trợ các trình vòng lặp proxy.

Trong STL, các trình vòng lặp có hai loại lợi ích đặc biệt liên quan: referencevalue_type. Cái trước là kiểu trả về của iterator operator*, và value_typelà kiểu (không tham chiếu, không tham chiếu) của các phần tử của chuỗi.

Các thuật toán chung thường có nhu cầu thực hiện những việc như thế này:

value_type tmp = *it;

... vì vậy chúng tôi biết rằng phải có một số mối quan hệ giữa hai loại này. Đối với các trình vòng lặp không proxy, mối quan hệ rất đơn giản: referenceluôn luôn value_type, tùy chọn const và tham chiếu đủ điều kiện. Những nỗ lực ban đầu trong việc xác định InputIteratorkhái niệm đòi hỏi biểu thức có thể *itchuyển đổi được const value_type &và đối với hầu hết các trình vòng lặp thú vị là đủ.

Tôi muốn các trình vòng lặp trong C ++ 20 mạnh hơn thế này. Ví dụ, hãy xem xét các nhu cầu của một zip_iteratorlặp đi lặp lại hai chuỗi trong bước khóa. Khi bạn hủy đăng ký a zip_iterator, bạn sẽ nhận được tạm thời pairhai loại lặp reference. Vì vậy, zip'a vector<int>và a vector<double>sẽ có các loại liên quan:

zipiterator's reference: pair<int &, double &>
zipiterator's value_type:pair<int, double>

Như bạn có thể thấy, hai loại này không liên quan với nhau chỉ đơn giản bằng cách thêm trình độ cv- và ref cấp cao nhất. Và để cho hai loại khác nhau tùy ý cảm thấy sai. Rõ ràng có một số mối quan hệ ở đây. Nhưng mối quan hệ là gì và những thuật toán chung có thể hoạt động trên các trình vòng lặp có thể giả định một cách an toàn về hai loại?

Câu trả lời trong C ++ 20 là đối với bất kỳ loại trình vòng lặp hợp lệ, proxy hay không, các loại reference &&value_type &chia sẻ một tham chiếu chung . Nói cách khác, đối với một số trình vòng lặp, itcó một số loại CRlàm cho các hình thức sau được hình thành rõ ràng:

void foo(CR) // CR is the common reference for iterator I
{}

void algo( I it, iter_value_t<I> val )
{
  foo(val); // OK, lvalue to value_type convertible to CR
  foo(*it); // OK, reference convertible to CR
}

CRlà tài liệu tham khảo phổ biến. Tất cả các thuật toán có thể dựa vào thực tế là loại này tồn tại và có thể sử dụng std::common_referenceđể tính toán nó.

Vì vậy, đó là vai trò common_referencetrong STL trong C ++ 20. Nói chung, trừ khi bạn đang viết các thuật toán chung hoặc các trình vòng lặp proxy, bạn có thể bỏ qua nó một cách an toàn. Nó nằm dưới vỏ bọc đảm bảo rằng các trình lặp của bạn đang đáp ứng các nghĩa vụ theo hợp đồng của họ.


EDIT: OP cũng yêu cầu một ví dụ. Đây là một chút giả tạo, nhưng hãy tưởng tượng nó C ++ 20 và bạn có một phạm vi truy cập ngẫu nhiên rcủa các loại Rvề mà bạn không biết gì, và bạn muốn sortphạm vi.

Hơn nữa hãy tưởng tượng rằng vì một số lý do, bạn muốn sử dụng một hàm so sánh đơn hình, như thế nào std::less<T>. (Có lẽ bạn đã type-xóa dãy núi này, và bạn cần phải cũng gõ-xóa chức năng so sánh và vượt qua nó thông qua một virtual? Một lần nữa, một căng ra.) Điều gì nên Tđược std::less<T>? Cho rằng bạn sẽ sử dụng common_reference, hoặc người trợ giúp iter_common_reference_tđược thực hiện về mặt đó.

using CR = std::iter_common_reference_t<std::ranges::iterator_t<R>>;
std::ranges::sort(r, std::less<CR>{});

Điều đó được đảm bảo để hoạt động, ngay cả khi phạm vi rcó các trình vòng lặp proxy.


2
Có thể tôi dày đặc, nhưng bạn có thể làm rõ những gì tham chiếu phổ biến trong ví dụ về cặp zip không?
happydave

4
Lý tưởng nhất, pair<T&,U&>pair<T,U>&sẽ có một tài liệu tham khảo chung, và nó sẽ đơn giản pair<T&,U&>. Tuy nhiên, đối std::pair, không có chuyển đổi từ pair<T,U>&tới pair<T&,U&>mặc dù một sự chuyển đổi đó là âm thanh về nguyên tắc. (Điều này, tình cờ, là lý do tại sao chúng ta không có zipchế độ xem trong C ++ 20.)
Eric Niebler

4
@EricNiebler: " Điều này, tình cờ, là lý do tại sao chúng tôi không có chế độ xem zip trong C ++ 20. " Có một số lý do tại sao một trình lặp zip sẽ phải sử dụng pair, thay vì một loại có thể được thiết kế riêng cho mục đích của nó , với chuyển đổi ngầm thích hợp khi cần thiết?
Nicol Bolas

5
@Nicol Bolas Không cần sử dụng std::pair; bất kỳ loại giống cặp nào phù hợp với các chuyển đổi phù hợp sẽ thực hiện và phạm vi-v3 xác định loại giống như cặp đó. Trong Ủy ban, LEWG không thích ý tưởng thêm vào Thư viện tiêu chuẩn một loại gần như nhưng không hoàn toàn std::pair, có thể là quy tắc hay không, mà không cần thực hiện chuyên sâu về những ưu và nhược điểm của việc đơn giản là làm std::pairviệc.
Eric Niebler

3
tuple, pair, tomato, to- MAH- to. paircó tính năng hay này mà bạn có thể truy cập các yếu tố với .first.second. Các ràng buộc có cấu trúc giúp với một số khó xử khi làm việc với tuples, nhưng không phải tất cả.
Eric Niebler
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.