简体   繁体   中英

Enhanced for loop with std::move_iterator

How does one iterate with the enhanced for loop using std::move_iterator ?

Would the following be sufficient?

for ( auto && element : collection )
    // std::move( element );

The example you provided is not sufficient, because auto&& element is not of the type as std::move_iterator . With auto&& element you will not be able not access the member functions of std::move_iterator .

In order to use an enhanced for loop in combination with std::move_iterator one needs to generate a vector of std::move_iterator s. Just like that:

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

int main() {

    std::vector<double> Vec = {1.1,2.2,3.3,4.4,5.5};

    typedef std::vector<double>::iterator iter_t;
    std::vector<std::move_iterator<iter_t>> MoItVec(Vec.size());

    std::generate(MoItVec.begin(), MoItVec.end(), 
        [&Vec,n = 0]() mutable
        { 
            auto It = Vec.begin() + n++;
            return  std::move_iterator<iter_t>(It);
        }
    );

    for(auto MoIt : MoItVec)
    {
        std::cout << *MoIt << std::endl;
        //do cool stuff with MoIt
    }

    return 0;
} 

You can run the above code online .

IMHO the approach described above is more complicated then just using a standard for loop:

for(auto It = Vec.begin(); It != Vec.end(); ++It)
{
    auto MoIt = std::move_iterator<iter_t>(It);
    //do cool stuff with MoIt
}

A note on auto&&: This doesn't always declare an rvalue reference, although it looks like it. auto&& is actually a universal reference (or forwarding reference ), meaning the type of "auto &&" deduced will be lvalue reference or rvalue reference, depending on whether we try to deduce the type of an lvalue or an rvalue.

It seems that you just want to move from the elements in your container. In this case, you can also just use normal references and then move from them:

void function(X&&);

for (auto& x: vector_of_x) {
    function(std::move(x));
}

Additional note: even if you assign the type rvalue reference in your for-loop and then call a function with it, like so:

for (X&& x: vector_of_x) {
    function(x);
}

this will not work if "function" is declared as above (accepting only rvalue references). This is because you actually pass in an lvalue (x), that just has type rvalue reference (X&&).

You can move from a variable in a range-based-for .

std::vector<std::unique_ptr<int>> v1;
v1.push_back(std::make_unique<int>(7));
v1.push_back(std::make_unique<int>(3));

moving items from the vector v1 to a new vector v2 :

// option 1
std::vector<std::unique_ptr<int>> v2;
for(auto& ptr : v1) {
    v2.push_back(std::move(ptr));
}

Note that we use auto& in the loop above and not auto&& , as the deduced type would anyhow be lvalue reference to unique_ptr (even if using forwarding reference : auto&&) - based on the return value of operator* on vector::iterator which is lvalue in our case 1 .

Another way to move items from vector v1 to a new vector v2 is:

// option 2
std::vector<std::unique_ptr<int>> v2 {
    std::make_move_iterator(v1.begin()),
    std::make_move_iterator(v1.end())
};

Both options are fine and result with the same outcome:

  • v1 holds two invalidated unique_ptrs
  • v2 holds two unique_ptrs, holding 7 and 3

1 The only case where looping over std::vector returns rvalue reference is with vector of bool .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM