2017-03-03 34 views
17
#include <vector> 
#include <iostream> 

using namespace std; 

int main() 
{ 
    vector<int> coll; 

    decltype(std::begin(std::declval<vector<int>>())) 
     pos_1 = coll.begin(); 
    auto pos_2 = coll.begin(); 

    cout << typeid(decltype(pos_1)).name() << endl; 
    cout << typeid(decltype(pos_2)).name() << endl; 
} 

Trình biên dịch của tôi là clang 4.0. Đầu ra là:Tại sao "std :: begin()" luôn trả về "const_iterator" trong trường hợp này?

class std::_Vector_const_iterator<class std::_Vector_val<struct std::_Simple_types<int> > > 
class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<int> > > 

Điều đó có nghĩa: pos_1 = pos_2; là ok, trong khi pos_2 = pos_1; không phải là ok.

Tại sao std::begin() luôn trả lại const_iterator thay vì iterator trong trường hợp này?

+1

tôi đoán là nó vì đó là bởi vì bạn đang suy diễn ra kiểu của 'pos_1' sử dụng tạm thời. Chúng chỉ liên kết với tham chiếu const và tất cả những thứ đó, đó là nơi const đến trong vở kịch. – Borgleader

Trả lời

21

Chức năng cuộc gọi:

std::declval<std::vector<int>>() 

kết quả trong biểu thức rvalue có thể được biểu thị là:

std::vector<int>&& 

Trình biên dịch có hai quá tải (generic) của std::begin để lựa chọn ([iterator.range]):

template <class C> 
auto begin(C& c) -> decltype(c.begin());  // #1 

template <class C> 
auto begin(const C& c) -> decltype(c.begin()); // #2 

Đối với một biểu rvalue, chỉ có tình trạng quá tải thứ hai (# 2) là khả thi - một rvalue không thể bị ràng buộc bởi một tham chiếu không phải lvalue. Trình độ const loại tham chiếu ngụ ý rằng trình biên dịch sẽ sử dụng quá tải có trình độ const của hàm begin thành viên:

const_iterator begin() const noexcept; 
//      ~~~~^ 

mà trả về một thể hiện của loại const_iterator.

Bạn có thể thay đổi hành vi đó bằng cách yêu cầu một biểu thức vế trái của std::vector<int> từ std::declval gọi:

decltype(std::begin(std::declval<std::vector<int>&>())) pos_1 = coll.begin(); 
//            ~~^~~  
+2

Điều thú vị cần lưu ý: nếu phiên bản thành viên 'không bắt đầu' đã được sử dụng, phiên bản có thể thay đổi sẽ được ưu tiên, trả về 'trình lặp'. Đây là một cách thành viên và không phải thành viên chức năng khác nhau – KABoissonneault

+0

@KABoissonneault Bạn có nghĩa là 'std :: declval >(). Begin()'? Có, đó là vì [\ [over.match.funcs \] /p5.1] (http://eel.is/c++draft/over.match.funcs#5.1). –

3

nếu bạn có Type&& (tạm thời) thì tình trạng quá tải có độ phân giải sẽ thích const Type& qua Type&, vì một ràng buộc sẽ không tạm thời để một tổ chức phi const vế trái tham khảo

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