使用C ++ 11在一行中连接两个std :: vectors

时间:2017-07-03 13:41:06

标签: c++ c++11 stdvector

有没有办法,使用C ++ 11,在一个代码行中连接两个std :: vector,第一个在局部变量中定义,第二个从函数返回:

#include <vector>
#include <iostream>
#include <iterator>

std::vector<int> getNewVector()
{
    return {4,5,6};
}

int main(int argc, char** argv)
{
  std::vector<int> dest;
  std::vector<int> src{1,2,3};

  dest = src + getNewVector(); //Error: no operator "+" matches these operands

  return 0;
}

编辑:this question不同,即不使用C ++ 11,我想知道新的C ++ 11标准是否提供了一些有用的功能,可以帮助我任务。 作为一个例子,我使用了+运算符,即使它不起作用,但只是想知道我在寻找什么。

5 个答案:

答案 0 :(得分:3)

您可以使用boost::range库轻松完成此操作。

范围将成为C ++标准库的一部分。有关详细信息,请参阅Ranges for the Standard Library

加分点:结果向量只有一个内存分配。

#include <vector>
#include <boost/range/join.hpp>

int main() {
    std::vector<int> a{1,2,3};
    std::vector<int> b{4,5,6};
    auto c = boost::copy_range<std::vector<int>>(boost::join(a, b));
}

或者,将其推广到两个以上的输入序列和类型:

template<class T, class U>
auto join(T const& a, U const& b) -> decltype(boost::join(a, b)) {
    return boost::join(a, b);
}

template<class T, class U, class... Args>
auto join(T const& a, U const& b, Args const&... args) -> decltype(boost::join(a, join(b, args...))) {
    return boost::join(a, join(b, args...));
}

int main() {
    std::vector<int> a{1,2,3};
    std::list<int> b{4,5,6};
    std::set<int> c{7,8,9};
    auto d = boost::copy_range<std::vector<int>>(join(a, b, c)); 
}

同样,它只在boost::copy_range<std::vector<int>>中进行一次内存分配,因为输入序列长度是已知的。

答案 1 :(得分:1)

我们可以利用将l值和r值传递给operator+的事实:

#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>

std::vector<int> getNewVector()
{
    return {4, 5, 6};
}

template <class T>
T operator+(const T& l, T&& r)
{
    T c{};
    c.reserve(l.size() + r.size());
    auto bi = std::back_inserter(c);
    std::copy(l.begin(), l.end(), bi);
    std::move(r.begin(), r.end(), bi);
    return c;
}

int main()
{
    std::vector<int> dest;
    std::vector<int> src{1, 2, 3};
    dest = src + getNewVector(); //uses operator "+"
    return 0;
}

答案 2 :(得分:1)

重载运算符+需要2x向量,没有库提升的解决方案

#include <vector>
#include <iostream>
template<typename T>
std::vector<T> operator+(std::vector<T> vec1, const std::vector<T>&& vec2)
{
    vec1.insert(vec1.end(), vec2.begin(), vec2.end());
    return vec1;
}
std::vector<int> getNewVector()
{
    return{ 4,5,6 };
}
template<typename T>
void displayVectors(const std::vector<T>& src, const std::vector<T>& dest, const std::vector<T>&& getNewVector)
{
    std::cout << "src { ";
    for (const auto& itr : src)
        std::cout << itr << " ";
    std::cout << "}" << std::endl;
    std::cout << "getNewVector() { ";
    for (const auto& itr : getNewVector)
        std::cout << itr << " ";
    std::cout << "}" << std::endl;
    std::cout << "dest { ";
    for (const auto& itr : dest)
        std::cout << itr << " ";
    std::cout << "}" << std::endl;
}
int main(int argc, char** argv)
{
    std::vector<int> dest;
    std::vector<int> src{ 1,2,3 };
    displayVectors(src, dest, getNewVector());
    dest = src + getNewVector();
    std::cout << "After operation" << std::endl;
    displayVectors(src, dest, getNewVector());
    return 0;
}

或使用移动词典

#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
template<typename T>
std::vector<T> operator+(std::vector<T> vec1, const std::vector<T>&& vec2)
{
    std::move(vec2.begin(), vec2.end(), std::back_inserter(vec1));
    return vec1;
}
std::vector<int> getNewVector()
{
    return{ 4,5,6 };
}
template<typename T>
void displayVectors(const std::vector<T>& src, const std::vector<T>& dest)
{
    std::cout << "src { ";
    for (const auto& itr : src)
        std::cout << itr << " ";
    std::cout << "}" << std::endl;
    std::cout << "dest { ";
    for (const auto& itr : dest)
        std::cout << itr << " ";
    std::cout << "}" << std::endl;
}
int main(int argc, char** argv)
{
    std::vector<int> dest;
    std::vector<int> src{ 1,2,3 };
    displayVectors(src, dest);
    dest = src + getNewVector();
    std::cout << "After operation" << std::endl;
    displayVectors(src, dest);
    return 0;
}

答案 3 :(得分:0)

namespace named_operator {
  template<class D>struct make_operator{make_operator(){}};

  template<class T, char, class O> struct half_apply { T&& lhs; };

  template<class Lhs, class Op>
  half_apply<Lhs, '+', Op> operator+( Lhs&& lhs, make_operator<Op> ) {
    return {std::forward<Lhs>(lhs)};
  }

  template<class Lhs, class Op, class Rhs>
  auto operator+( half_apply<Lhs, '+', Op>&& lhs, Rhs&& rhs )
  -> decltype( named_invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) ) )
  {
    return named_invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
  }
}
首先是

样板库,然后是:

namespace ops {
  struct concat_t:named_operator::make_operator<concat_t>{};
  static const concat_t concat{};
  template<class T, class A, class A2>
  std::vector<T,A> named_invoke( std::vector<T,A> lhs, concat_t, std::vector<T,A2> const& rhs){
    lhs.insert(lhs.end(), rhs.begin(), rhs.end());
    return std::move(lhs);
  }
}
using ops::concat;

+concat+运算符。最终用途如下:

int main(){
   std::vector<int> a{1,2,3};
   std::vector<int> b{7,8,9};

  for( auto x: a +concat+ a +concat+ b )
    std::cout <<x<<'\n';
}

Live example

重载裸+std中是非法的,在根命名空间中是脆弱/危险的。由于&#34;在子名称空间中的脆弱而不起作用&#34;,如果你太贪心会很危险。 concat_t标记类型可以避免这两种情况。

谁想要调用一个函数。带有()的前缀表示法令链条烦恼。

以上复制左手边(除非lhs是临时的),然后将rhs连接起来。将move-contents添加到rhs是另一个名称空间ops中的命名调用函数。因此a+a+b复制a,然后将副本扩展两次。

对于通常的问题,表达式模板版本可以避免多次调整大小调整大小。

答案 4 :(得分:-1)

根据Maxim Egorushkin的建议

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

会更有效率。

如果你想修改&#39; b&#39;的值,请在代码下面使用std :: transform。并插入到&#39;

std::transform( b.begin(), b.end(), std::back_inserter(a), [](int i)->int   { return i + delta; } );

完整代码

int main()
{
    std::vector<int> a = {1,2,3,4,5};
    std::vector<int> b = {11,22,33,44,55};   

//to copy
 a.insert(a.end(), b.begin(), b.end());

//to transform
    std::transform( b.begin(), b.end(), std::back_inserter(a), [](int i)->int   { return i + delta; } );

    return 0;
}