Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

c++20 template parameter of random_access_iterator concept, cannot accept iterator type?

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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?

>Solution :

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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading