#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;
}
My compiler is clang 4.0. The output is:
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> > >
That means: pos_1 = pos_2;
is ok, while pos_2 = pos_1;
is not ok.
Why does std::begin()
always return const_iterator
rather than iterator
in such a case?
The function call:
std::declval<std::vector<int>>()
results in an rvalue expression that can be denoted as:
std::vector<int>&&
The compiler has two (generic) overloads of std::begin
to choose from ([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
For an rvalue expression, only the second overload (#2) is viable -- an rvalue cannot be bound by a non-const lvalue reference. The const qualification of the referenced type implies that the compiler will use the const qualified overload of the begin
member function:
const_iterator begin() const noexcept;
// ~~~~^
which returns an instance of type const_iterator
.
You can change that behavior by requesting an lvalue expression of std::vector<int>
from the std::declval
call:
decltype(std::begin(std::declval<std::vector<int>&>())) pos_1 = coll.begin();
// ~~^~~
if you have Type&&
(a temporary) then overload-resolution
will prefer const Type&
over Type&
, since
a temporary wont bind to a non-const lvalue-reference
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With