2017-03-03 148 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; 
} 

我的編譯器是鐺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

回答

21

函數調用:

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)。 –

3

,如果你有Type&&(臨時),然後重載分辨率 會喜歡const Type&超過Type&,因爲 暫時不會綁定到非const左值參考

相關問題