2016-11-18 4 views
4

Angenommen, ich habe einige Code wie folgt aus:Kann ich Elemente aus einem Bereich basierend verschieben?

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 
} 

Ich frage mich nur, wenn der Compiler kann (ich kann entweder VS2015 oder gcc 6) optimieren, um die Elemente in for-Schleife zu bewegen. Oder was soll ich tun, damit es einzieht, da die Saite ziemlich lang sein kann.

Würde ein alter beginnen für Schleife oder eine Koroutinenhilfe zu enden?

+0

@songyuanyao, Wird nicht nur eine Weiterleitungsreferenz an den Wert gebunden, der vom Iterator 'operator *' zurückgegeben wird? Und da der Iterator einen lvalue-Verweis auf "std :: string" zurückgibt, wird "std :: string &&&" auf "std :: string &" reduziert. [Hier ein Beispiel] (http://coliru.stacked-crooked.com/a/14efce4c332a8b9f) – Alejandro

+0

@ Alejandro Ich denke, du hast Recht. – songyuanyao

Antwort

5

Wenn Sie von diesem Vektor zu some_function() Elemente bewegen, nur tun move ausdrücklich:

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


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

sonst ist es nicht klar, was Sie mit Elementen in for-Schleife zu bewegen.

1

Nur auto& mit expliziten std::move ist genug.

Aber

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));} 
); 
} 

Nun, abgesehen von Tippfehler,

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

Will haben i ist ein fahrener von Kopie jedes Elements Phantasie zu sein.

Aber das ist verrückt.

Diese Technik kann nützlich sein, wenn Sie ranfe/containerbasierten Code iterieren, der move-agnostic sein soll.

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; 
} 

Jetzt, mit move_from(x) als „Bereich“ den obigen Aufruf ist anders, als es mit x aufrufen. Sie können sich auch andere Algorithmen vorstellen, die so geschrieben sind.

+0

_Aber das ist verrückt_ - dieses Mal muss ich zustimmen: auch wenn es mir gefällt, macht es für das OP wenig Sinn. :-) – skypjack

Verwandte Themen