为什么在这种情况下“std :: begin()”总是返回“const_iterator”?

问题描述:

#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; 
} 

我的编译器是铛4.0。输出是:为什么在这种情况下“std :: begin()”总是返回“const_iterator”?

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> > > 

这意味着:pos_1 = pos_2;是确定的,而pos_2 = pos_1;也不行。

为什么在这种情况下std::begin()总是返回const_iterator而不是iterator

+1

我的猜测是,那是因为它是因为推导的youre的pos_1''使用临时类型。它们只绑定到const引用和所有这些,这是const在游戏中的地方。 – Borgleader

函数调用:

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

导致一个rvalue表达式可以表示为:

std::vector<int>&& 

编译器具有std::begin两(通用)重载从([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 

对于一个右值表达,只有第二过载(#2)是可行的 - 右值不能由约束非常量左值引用。被引用的类型的常量资格意味着,编译器将使用begin成员函数的常量合格过载:

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

返回const_iterator类型的一个实例。

您可以通过从std::declval呼叫请求的std::vector<int>左值表达式改变这种行为:

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

有趣的是:如果已经使用了非'static'成员版本的'begin',那么可变版本将会是首选,返回'iterator'。这是成员和非成员函数不同的一种方式 – KABoissonneault

+0

@KABoissonneault你的意思是'std :: declval >()。begin()'?是的,那是因为[\ [over.match.funcs \] /p5.1](http://eel.is/c++draft/over.match.funcs#5.1)。 –

,如果你有Type&&(临时),然后重载分辨率 会喜欢const Type&超过Type&,因为 暂时不会绑定到非const左值参考