For c 20 concept, I had a quick test:
#include<iostream>
#include<vector>
using namespace std;
template <random_access_iterator I>
void advance(I &iter, int n) {
cout << "random_access_iterator" << '\n';
}
int main() {
vector vec{1, 2, 3};
{
vector<int>::iterator itRa = vec.begin();
advance(itRa, 2);
}
advance(vec.begin(), 3); // compilation error!
return 0;
}
I run clang 14 on windows10 and it prints:
clang .\MyAdvance.cpp -std=c 20
candidate function [with _InIt =
std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>, _Diff =
int] not viable: expects an lvalue for 1st argument
_CONSTEXPR17 void advance(_InIt& _Where, _Diff _Off) { // increment iterat...
^
.\MyAdvance.cpp:6:6: note: candidate function [with I =
std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>] not
viable: expects an lvalue for 1st argument
void advance(I &iter, int n) {
^
1 error generated.
Very strange, what's the difference between:
vector<int>::iterator itRa = vec.begin();
advance(itRa, 2);
and
advance(vec.begin(), 3); // compilation error!
Why the 1st version gets compiled and 2nd version doesn't?
CodePudding user response:
begin()
returns an iterator by-value, meaning the call expression is a prvalue. You can't pass a prvalue as an argument to a non-const
lvalue reference parameter. That is not specific to iterators. It applies to any type, e.g.
void f(int&);
//...
f(1234); // fails because 1234 is a prvalue
To allow for prvalues as argument as well you would need to add another overload with I&&
instead of I&
argument type:
template <random_access_iterator I>
void advance(I &&iter, int n) {
cout << "random_access_iterator" << '\n';
}
But that doesn't really make sense. Why should it be allowed to advance an iterator which is then immediately destroyed? If someone writes advance(vec.begin(), 3)
then that must be a mistake and it is good that it produces an error since that expression has no effect at all.