假设我有2个标准向量:
vector<int> a;
vector<int> b;
我们也说两者都有大约30个元素。
肮脏的方式是迭代b并通过vector<int>::push_back()
添加每个元素,尽管我不想这样做!
答案 0 :(得分:1059)
a.insert(a.end(), b.begin(), b.end());
或
a.insert(std::end(a), std::begin(b), std::end(b));
第二种变体是更通用的解决方案,因为b
也可以是一个数组。但是,它需要C ++ 11
答案 1 :(得分:76)
std::copy (b.begin(), b.end(), std::back_inserter(a));
如果向量a中的项没有赋值运算符(例如const成员),则可以使用它。
在所有其他情况下,与上述插入溶液相比,此解决方案是无效的。
答案 2 :(得分:35)
虽然说“编译器可以保留”,但为什么还要依赖它?那么移动语义的自动检测呢?那么用begin
和end
s重复容器名称的所有内容呢?
你知道吗,你想要的更简单吗?
(向下滚动到main
以获得妙语)
#include <type_traits>
#include <vector>
#include <iterator>
#include <iostream>
template<typename C,typename=void> struct can_reserve: std::false_type {};
template<typename T, typename A>
struct can_reserve<std::vector<T,A>,void>:
std::true_type
{};
template<int n> struct secret_enum { enum class type {}; };
template<int n>
using SecretEnum = typename secret_enum<n>::type;
template<bool b, int override_num=1>
using EnableFuncIf = typename std::enable_if< b, SecretEnum<override_num> >::type;
template<bool b, int override_num=1>
using DisableFuncIf = EnableFuncIf< !b, -override_num >;
template<typename C, EnableFuncIf< can_reserve<C>::value >... >
void try_reserve( C& c, std::size_t n ) {
c.reserve(n);
}
template<typename C, DisableFuncIf< can_reserve<C>::value >... >
void try_reserve( C& c, std::size_t ) { } // do nothing
template<typename C,typename=void>
struct has_size_method:std::false_type {};
template<typename C>
struct has_size_method<C, typename std::enable_if<std::is_same<
decltype( std::declval<C>().size() ),
decltype( std::declval<C>().size() )
>::value>::type>:std::true_type {};
namespace adl_aux {
using std::begin; using std::end;
template<typename C>
auto adl_begin(C&&c)->decltype( begin(std::forward<C>(c)) );
template<typename C>
auto adl_end(C&&c)->decltype( end(std::forward<C>(c)) );
}
template<typename C>
struct iterable_traits {
typedef decltype( adl_aux::adl_begin(std::declval<C&>()) ) iterator;
typedef decltype( adl_aux::adl_begin(std::declval<C const&>()) ) const_iterator;
};
template<typename C> using Iterator = typename iterable_traits<C>::iterator;
template<typename C> using ConstIterator = typename iterable_traits<C>::const_iterator;
template<typename I> using IteratorCategory = typename std::iterator_traits<I>::iterator_category;
template<typename C, EnableFuncIf< has_size_method<C>::value, 1>... >
std::size_t size_at_least( C&& c ) {
return c.size();
}
template<typename C, EnableFuncIf< !has_size_method<C>::value &&
std::is_base_of< std::random_access_iterator_tag, IteratorCategory<Iterator<C>> >::value, 2>... >
std::size_t size_at_least( C&& c ) {
using std::begin; using std::end;
return end(c)-begin(c);
};
template<typename C, EnableFuncIf< !has_size_method<C>::value &&
!std::is_base_of< std::random_access_iterator_tag, IteratorCategory<Iterator<C>> >::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 <iostream>
template<typename C1, typename C2>
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<C2&&>;
c1.insert( end(c1),
try_make_move_iterator(begin(c2), is_rvref{}),
try_make_move_iterator(end(c2), is_rvref{}) );
return std::forward<C1>(c1);
}
struct append_infix_op {} append;
template<typename LHS>
struct append_on_right_op {
LHS lhs;
template<typename RHS>
LHS&& operator=( RHS&& rhs ) {
return append_containers( std::forward<LHS>(lhs), std::forward<RHS>(rhs) );
}
};
template<typename LHS>
append_on_right_op<LHS> operator+( LHS&& lhs, append_infix_op ) {
return { std::forward<LHS>(lhs) };
}
template<typename LHS,typename RHS>
typename std::remove_reference<LHS>::type operator+( append_on_right_op<LHS>&& lhs, RHS&& rhs ) {
typename std::decay<LHS>::type retval = std::forward<LHS>(lhs.lhs);
return append_containers( std::move(retval), std::forward<RHS>(rhs) );
}
template<typename C>
void print_container( C&& c ) {
for( auto&& x:c )
std::cout << x << ",";
std::cout << "\n";
};
int main() {
std::vector<int> a = {0,1,2};
std::vector<int> 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<double> d = ( std::vector<double>{-3.14, -2, -1} +append= a );
print_container(d);
std::vector<double> c = std::move(d) +append+ a;
print_container(c);
print_container(d);
std::vector<double> e = c +append+ std::move(a);
print_container(e);
print_container(a);
}
现在使用move-data-from-rhs,append-array-to-container,附加forward_list-to-container,move-container-from-lhs,感谢@DyP的帮助。
请注意,由于EnableFunctionIf<>...
技术,上面的代码无法在clang中编译。在clang this workaround中工作。
答案 3 :(得分:26)
如果您想向其自身添加矢量,两种流行的解决方案都将失败:
std::vector<std::string> 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" }