2015-05-26 10 views
6

Vì vậy, để cho phép mã nhưVới cbegin(), cend(), tại sao không có cfront(), cback(), cfind(), ...?

auto vect = ...; 
auto it = vect.begin(), end = vect.end(); // want const_iterator, getting iterator 

để chọn quá tải phải begin()end(), ngay cả đối với container không const thì rõ ràng hơn cbegin()/cend() chức năng được thêm vào.

Tại sao dừng lại ở đó?

Vùng chứa liên kết có phương thức find() có cùng vấn đề. Các vùng chứa chuỗi có front()back(), một lần nữa với cùng một vấn đề.

Các thiếu phiên bản const thiếu rõ ràng này hoặc theo thiết kế?

+1

Chúng bị quá tải, tức là'const_reference front() const;' và 'tham chiếu front();' – jrok

+0

Tôi không thấy cần có hàm 'cfront'. Vấn đề quan trọng sẽ giải quyết là gì? 'cbegin' /' cend' được yêu cầu khá thường xuyên, đó là sự biện minh cho nhóm làm việc để giới thiệu hàm đó. – Columbo

+1

@Columbo: ai đang đếm bao nhiêu lần sử dụng các chức năng không tồn tại trong tổng số các chương trình C++? Tôi biết ủy ban là một vòng tròn của các trình thuật sĩ, nhưng họ có thể đọc được suy nghĩ của tất cả các nhà phát triển C++ là mới đối với tôi. Nghiêm túc, mặc dù, tiêu chuẩn C++ không phải là một cuộc thi phổ biến. Nếu bạn thêm một cơ chế mới, bạn nên thêm nó ở mọi nơi nó hữu ích, không dừng lại nửa chừng, hay bạn nên? –

Trả lời

7

API rộng hơn có chi phí, thậm chí chỉ cần bỏ qua nó khi tìm kiếm hàm bạn muốn.

template<class T> 
T const as_const(T&& t) noexcept(noexcept(T(std::declval<T>())) { 
    return std::forward<T>(t); 
} 
template<class T> 
T const& as_const(T& t) noexcept { 
    return t; 
} 

thực hiện hầu hết những gì bạn muốn. Nó thậm chí sẽ làm cho cbegin lỗi thời.

(sửa đổi thực hiện để mã dựa tắt trên n4380 cung cấp bởi @TC dưới đây. Mã khác, bởi vì tôi nghĩ n4380 nhận nó hơi sai trong trường hợp T&&.)

+1

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4380.html –

+0

@ t.c. thời gian đi du lịch đạo văn! – Yakk

+0

Tôi thích 'as_const' :) Hãy hy vọng' cbegin() '/' cend() 'sẽ không được dùng nữa một cách nhanh chóng, bởi vì một API không phù hợp có chi phí cao hơn. –

3

Mục đích của cbegin/cend là để giải quyết một vấn đề cụ thể. Hãy xem xét mã này:

std::vector<int> & v = //... v is a non-const reference 

// For clarity, I want this iterator to be a const_iterator. 
// This works because iterator is implicitly convertible to const_iterator 
std::vector<int>::const_iterator iter = find(v.begin(),v.end(),42); 

// (1) Now I want to use iter in an algorithm 
std::find(iter, v.end(), 38); //Error, can not deduce the template parameter for Iter. 

// (2) This works 
std::find(iter, const_cast<const std::vector<int> &>(v).end(), 38); 

// (3) This is the same as (2). 
std::find(iter, v.cend(), 38); 

Vấn đề là, do cách mẫu quy định khấu trừ làm việc, trình biên dịch không thể suy ra lập luận mẫu iterator trong báo cáo (1), vì Container::iteratorContainer::const_iterator là (khả năng) hai hoàn toàn các loại không liên quan (ngay cả khi loại trước đây có thể chuyển đổi ngầm ở dạng sau).

Câu lệnh (2) không chính xác là đường thẳng, đó là lý do tại sao chúng tôi cầncend().

Bây giờ, front(), back() et similia tất cả trở lại tham chiếu. Một tài liệu tham khảo không const luôn có thể được suy luận như const trong một chức năng templated, đó là:

template<class T> void f(const T & l, const T & r); 

int main() 
{ 
    int x; vector<int> v; 

    //This will works even if the return type of front() is int&. 
    f(x, v.front()); 
} 

Kể từ Container::const_reference là yêu cầu của tiêu chuẩn để được bằng const Container::value_type &, cfront()/cback() không mua chúng tôi bất cứ điều gì.


Điều đáng nói là thư viện vùng chứa khác (xem bạn Qt) được triển khai bằng cách sử dụng Sao chép-ghi-ghi. Điều này có nghĩa là việc gọi hàm const trên vùng chứa đó có khả năng rẻ hơn nhiều so với việc gọi phiên bản không phải là const tương đương, đơn giản là vì không phải const có thể sao chép toàn bộ vùng chứa dưới mui xe.

Vì lý do này, các thùng chứa Qt có rất nhiều constFunction trong giao diện của họ và người dùng có quyền tự do chọn đúng.

+0

Tôi đã có ấn tượng rằng 'cbegin()' và 'cend()' là để nhận đúng loại trong khai báo biến tự động. Và có, các thùng chứa Qt có vấn đề tách (cũng như 'std :: string' trong libstdC++). –

+0

'const Container :: reference' và' const Container :: value_type & '(aka' Container :: const_reference') là những thứ rất khác nhau. –

+0

@ T.C. Bạn đúng rồi. Tôi sẽ chỉnh sửa câu trả lời của mình. – sbabbi

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