重载复合赋值运算符的规范方法是什么?

时间:2014-10-18 19:21:55

标签: c++ c++11

似乎是一个棘手的问题,因为你无法向vector添加新的成员函数。此表单避免了最少量的副本:

std::vector<T>& operator+=(std::vector<T>& lhs, const std::vector<T>& rhs)

但是自我分配失败了,所以唯一适用于自我分配的是:

template <typename T>
std::vector<T>& operator+=(std::vector<T>& lhs, std::vector<T> rhs)
{
    lhs.insert(lhs.end(), rhs.begin(), rhs.end());
    return lhs;
}

但这需要额外的副本。这样做的正确方法是什么?

在我的问题中,上述形式“不能正常工作”是模棱两可的。因为它们似乎适用于整数(尽管不适用于std :: strings)。有人指出这是因为它未定义的行为。

2 个答案:

答案 0 :(得分:3)

问题:

template <typename T>
std::vector<T>& operator+=(std::vector<T>& lhs, const std::vector<T>& rhs)
{
    lhs.insert(lhs.end(), rhs.begin(), rhs.end());
    return lhs;
}

不是签名,它将传递给insert的迭代器在插入完成之前变为无效。

只需使用the correct technique for appending a vector to itself,无需额外的副本。

template <typename T>
void concat_in_place(std::vector<T>& lhs, const std::vector<T>& rhs)
{
    auto left_count = lhs.size();
    auto right_count = rhs.size();
    lhs.resize(left_count + right_count);
    std::copy_n(rhs.begin(), right_count, lhs.begin() + left_count);
}

答案 1 :(得分:0)

作为一项政策问题,您不应该使用它们之间的运算符来重载两个不同的std类型。它可能是未定义的行为:标准是模棱两可的。

如果您想在std容器上使用运算符语法,我建议使用命名运算符。它也更清楚,因为向量上的运算符可以是容器运算符或元素运算符,这就是它们默认缺失的原因。 v +append= v2;显然正在追加。 (创建一个静态追加对象,并使用向量重载其lhs和rhs运算符,并在中间步骤中使用表达式模板)

// mini named operator library.  Only supports + for now:
template<class Kind>
struct named_operator {};
template<class OP, class LHS> struct plus_ {
  LHS lhs;
  template<class RHS>
  decltype(auto) operator=(RHS&&rhs)&&{
    return plus_assign(std::forward<LHS>(lhs), OP{}, std::forward<RHS>(rhs));
  }
  template<class RHS>
  decltype(auto) operator+(RHS&&rhs)&&{
    return plus(std::forward<LHS>(lhs), OP{}, std::forward<RHS>(rhs));
  }
};
template<class Tag, class LHS>
plus_<Tag,LHS> operator+( LHS&& lhs, named_operator<Tag> ) {
  return {std::forward<LHS>(lhs)};
}

// creating a named operator:
static struct append_tag:named_operator<append_tag> {} append;

// helper function, finds size of containers and arrays:
template<class T,std::size_t N>
constexpr std::size_t size( T(&)[N] ) { return N; }
template<class C>
constexpr auto size(C&& c)->decltype(c.size()) { return c.size(); }

// implement the vector +append= range:
template<class T, class A, class RHS>
std::vector<T,A>& plus_assign(std::vector<T,A>&lhs, append_tag, RHS&& rhs) {
  auto rhs_size = size(rhs);
  lhs.reserve(lhs.size()+rhs_size);
  using std::begin; using std::end;
  copy_n( begin(rhs), rhs_size, back_inserter(lhs) );
  return lhs;
}
// implement container +append+ range:
template<class LHS, class RHS>
LHS plus( LHS lhs, append_tag, RHS&& rhs ) {
  using std::begin; using std::end; using std::back_inserter;
  copy_n( begin(rhs), size(rhs), back_inserter(lhs) );
  return std::move(lhs);
}

live example

请注意,std::vector<int> +append= std::list<int> +append+ std::array<double, 3>适用于上述代码。