Aggiunta di un vettore a un vettore

Supponendo che ho 2 vettori standard:

vector a; vector b; 

Diciamo anche che entrambi hanno circa 30 elementi.

  • Come aggiungo il vettore b alla fine del vettore a?

Il modo sporco sarebbe scorrere iterando b e aggiungendo ogni elemento tramite vector::push_back() , anche se non mi piacerebbe farlo!

 a.insert(a.end(), b.begin(), b.end()); 

o

 a.insert(std::end(a), std::begin(b), std::end(b)); 

La seconda variante è una soluzione più genericamente applicabile, dato che b potrebbe anche essere una matrice. Tuttavia, richiede C ++ 11

 std::copy (b.begin(), b.end(), std::back_inserter(a)); 

Questo può essere usato nel caso in cui gli elementi nel vettore a non abbiano un operatore di assegnazione (ad esempio un membro const).

In tutti gli altri casi questa soluzione è inefficace rispetto alla soluzione inserto sopra.

Mentre si dice “il compilatore può prenotare”, perché contare su di esso? E per quanto riguarda il rilevamento automatico della semantica del movimento? E che dire di tutto quel ripetersi del nome del contenitore con le begin s e le end s?

Non vorresti qualcosa, lo sai, più semplice?

(Scorrere verso il basso fino alla linea main per la battuta finale)

 #include  #include  #include  #include  template struct can_reserve: std::false_type {}; template struct can_reserve,void>: std::true_type {}; template struct secret_enum { enum class type {}; }; template using SecretEnum = typename secret_enum::type; template using EnableFuncIf = typename std::enable_if< b, SecretEnum >::type; template using DisableFuncIf = EnableFuncIf< !b, -override_num >; template::value >... > void try_reserve( C& c, std::size_t n ) { c.reserve(n); } template::value >... > void try_reserve( C& c, std::size_t ) { } // do nothing template struct has_size_method:std::false_type {}; template struct has_size_method().size() ), decltype( std::declval().size() ) >::value>::type>:std::true_type {}; namespace adl_aux { using std::begin; using std::end; template auto adl_begin(C&&c)->decltype( begin(std::forward(c)) ); template auto adl_end(C&&c)->decltype( end(std::forward(c)) ); } template struct iterable_traits { typedef decltype( adl_aux::adl_begin(std::declval()) ) iterator; typedef decltype( adl_aux::adl_begin(std::declval()) ) const_iterator; }; template using Iterator = typename iterable_traits::iterator; template using ConstIterator = typename iterable_traits::const_iterator; template using IteratorCategory = typename std::iterator_traits::iterator_category; template::value, 1>... > std::size_t size_at_least( C&& c ) { return c.size(); } template::value && std::is_base_of< std::random_access_iterator_tag, IteratorCategory> >::value, 2>... > std::size_t size_at_least( C&& c ) { using std::begin; using std::end; return end(c)-begin(c); }; template::value && !std::is_base_of< std::random_access_iterator_tag, IteratorCategory> >::value, 3>... > std::size_t size_at_least( C&& c ) { return 0; }; template < typename It > auto try_make_move_iterator(It i, std::true_type) -> decltype(make_move_iterator(i)) { return make_move_iterator(i); } template < typename It > It try_make_move_iterator(It i, ...) { return i; } #include  template C1&& append_containers( C1&& c1, C2&& c2 ) { using std::begin; using std::end; try_reserve( c1, size_at_least(c1) + size_at_least(c2) ); using is_rvref = std::is_rvalue_reference; c1.insert( end(c1), try_make_move_iterator(begin(c2), is_rvref{}), try_make_move_iterator(end(c2), is_rvref{}) ); return std::forward(c1); } struct append_infix_op {} append; template struct append_on_right_op { LHS lhs; template LHS&& operator=( RHS&& rhs ) { return append_containers( std::forward(lhs), std::forward(rhs) ); } }; template append_on_right_op operator+( LHS&& lhs, append_infix_op ) { return { std::forward(lhs) }; } template typename std::remove_reference::type operator+( append_on_right_op&& lhs, RHS&& rhs ) { typename std::decay::type retval = std::forward(lhs.lhs); return append_containers( std::move(retval), std::forward(rhs) ); } template void print_container( C&& c ) { for( auto&& x:c ) std::cout << x << ","; std::cout << "\n"; }; int main() { std::vector a = {0,1,2}; std::vector b = {3,4,5}; print_container(a); print_container(b); a +append= b; const int arr[] = {6,7,8}; a +append= arr; print_container(a); print_container(b); std::vector d = ( std::vector{-3.14, -2, -1} +append= a ); print_container(d); std::vector c = std::move(d) +append+ a; print_container(c); print_container(d); std::vector e = c +append+ std::move(a); print_container(e); print_container(a); } 

hehe .

Ora con move-data-from-rhs, append-array-to-container, aggiungi forward_list-to-container, move-container-from-lhs, grazie alla guida di @DyP.

Nota che quanto sopra non viene compilato in clang grazie alla tecnica EnableFunctionIf<>... In clang questa soluzione funziona.

Se vuoi aggiungere un vettore a se stesso, entrambe le soluzioni popolari falliranno:

 std::vector v, orig; orig.push_back("first"); orig.push_back("second"); // BAD: v = orig; v.insert(v.end(), v.begin(), v.end()); // Now v contains: { "first", "second", "", "" } // BAD: v = orig; std::copy(v.begin(), v.end(), std::back_inserter(v)); // std::bad_alloc exception is generated // GOOD, but I can't guarantee it will work with any STL: v = orig; v.reserve(v.size()*2); v.insert(v.end(), v.begin(), v.end()); // Now v contains: { "first", "second", "first", "second" } // GOOD, but I can't guarantee it will work with any STL: v = orig; v.reserve(v.size()*2); std::copy(v.begin(), v.end(), std::back_inserter(v)); // Now v contains: { "first", "second", "first", "second" } // GOOD (best): v = orig; v.insert(v.end(), orig.begin(), orig.end()); // note: we use different vectors here // Now v contains: { "first", "second", "first", "second" }