Anexando um vetor a um vetor

Supondo que eu tenha 2 vetores padrão:

vector a; vector b; 

Vamos dizer também que ambos têm cerca de 30 elementos.

  • Como adiciono o vetor b ao final do vetor a?

O jeito sujo seria iterar através de b e adicionar cada elemento via vector::push_back() , embora eu não gostaria de fazer isso!

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

ou

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

A segunda variante é uma solução mais genericamente aplicável, já que b também pode ser uma matriz. No entanto, requer C ++ 11

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

Isso pode ser usado caso os itens no vetor a não tenham nenhum operador de atribuição (por exemplo, membro const).

Em todos os outros casos, esta solução é ineficaz em comparação com a solução de inserção acima.

Ao dizer “o compilador pode reservar”, por que confiar nele? E a detecção automática da semântica de movimento? E quanto a toda essa repetição do nome do contêiner com o begin e o end ?

Você não quereria algo, você sabe, mais simples?

(Role para baixo para o main para o punchline)

 #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 .

Agora, com move-data-from-rhs, anexe-array-a-container, anexe forward_list-to-container, mova-container-from-lhs, graças à ajuda do @DyP.

Note que o acima não compila em clang graças à técnica EnableFunctionIf<>... No clang esta solução alternativa funciona.

Se você gostaria de adicionar vetor a si mesmo, ambas as soluções populares falharão:

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