c++ - c++:追加一个向量到向量

  显示原文与译文双语对照的内容

这个问题已经有了如下答案:

假设我有 2个STL向量:


vector<int> a;
vector<int> b;

让我们同时说,两个元素有大约 30个元素。

  • 如何将向量b 添加到向量的末尾?

肮脏的方式将遍历通过 vector<int>::push_back() b和添加每个元素,虽然我不愿意这么做!

时间:

当说"编译器可以保留"时,为什么要依靠它? 关于移动语义的自动检测? 那么,这些重复的容器名称和 beginend的名称又如何?

你不想要什么,你知道,简单一点?

( 向下滚动到 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);
}

y

现在使用 move-data-from-rhs,append-array-to-container,附加 forward_list-to-container,move-container-from-lhs,感谢 @DyP's 帮助。

注意,由于 EnableFunctionIf<>... 技术的不同,上面的代码无法编译。 在 clang 中,这个解决方法。

如果你想向它的自身添加向量,那么流行的解决方案将会失败:


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

...