2016-11-18 2 views
4

Предположим, у меня есть некоторый код, как это:Могу ли я перемещать элементы из диапазона?

std::vector<std::string> produce(const std::string& str){ 
    // create a vector based on input 
} 

void consume(const std::string& str){ 
    for (auto i:produce(str)) 
     // do some thing that use the str 
     // and I'd like to move it from the vector 
     some_process(str) // for example, move into this function 
} 

Мне просто интересно, если компилятор (я могу использовать либо VS2015 или GCC 6) можно оптимизировать для перемещения элементов в для петли. Или что мне делать, чтобы заставить его двигаться, поскольку строка может быть довольно длинной.

Может ли старый начинать кончать с помощью петли или справки coroutine?

+0

@songyuanyao, Не будет ли это просто привязать ссылку пересылки к значению, возвращаемому оператором '' '' 'итератора ''? И так как итератор возвращает ссылку lvalue на 'std :: string',' std :: string & && 'сворачивается вниз до' std :: string & '. [Вот пример] (http://coliru.stacked-crooked.com/a/14efce4c332a8b9f) – Alejandro

+0

@Alejandro Я думаю, что вы правы. – songyuanyao

ответ

5

Если вы хотите переместить элементы из этого вектора к some_function() вобще move явно:

void some_function(std::string str); 
void some_function(std::string &&str); // or explicitly 


for(auto &i:produce(str)) 
    some_function(std::move(i)); 

иначе не понятно, что вы имеете в виду, перемещая элементы в цикл.

1

Всего auto& с явным std::move достаточно.

Но чтобы быть фантазии

struct empty_t{}; 
template<class It,class B=empty_t>struct range_t:B{ 
    It b,e; 
    It begin()const{return b;} 
    It end()const{return e;} 
    range_t(It s,It f):b(std::move(s)),e(std::move(f)){} 
    // fancy 
    template<class S, class F> 
    range_t(B base, S s, F f):B(std::move(base)),b(s(*this)),e(f(*this)){} 
}; 
template<class It>range_t<It> range(It b, It e){return{std::move(b),std::move(e)};} 
template<class B, class S, class F> 
auto range(B base, S s, F f){ 
    auto It=std::result_of_t<s(base)>; 
    return range_t<It,B>{ 
    std::move(base),std::move(s),std::move(f) 
    }; 
} 
template<class R> 
auto move_from(R& r){ 
    using std::begin; using std::end; 
    return range(std::make_move_iterator(begin(r)), std::make_move_iterator(end(r))); 
} 
template<class R> 
auto move_from(R&& r){ 
    using std::begin; using std::end; 
    return range(
    std::move(r), 
    [](auto&r){return std::make_move_iterator(begin(r));}, 
    [](auto&r){return std::make_move_iterator(end(r));} 
); 
} 

Теперь, запрещая опечаток,

for(auto i:move_from(produce(str))) 
    some_function(std::move(i)); 

будет иметь i быть перемещены из-копии каждого элемента.

Но это безумие.

Этот метод может быть полезен, если у вас есть итерационный код, основанный на ране/контейнере, который вы хотите быть агностическим.

template<class R, class F> 
auto transform_to_vector(R&& r, F&& f){ 
    using std::begin; using std::end; 
    using rT=std::decay_t<std::result_of_t< f(*begin(std::forward<R>(r))) >>; 
    std::vector<rT> retval; 
    for(auto&& e:std::forward<R>(r)){ 
    retval.push_back(f(decltype(e)(e))); 
    } 
    return retval; 
} 

Теперь, вызвав выше move_from(x) как ваш «диапазон» отличается от вызова его с x. Вы могли бы представить и другие алгоритмы, написанные так же.

+0

_Но это безумие - на этот раз я должен согласиться: даже если мне это нравится, это не имеет особого смысла для ОП. :-) – skypjack

Смежные вопросы