2014-10-18 23 views
1

似乎是一个棘手的问题,因为你不能添加新的成员函数向量。这种形式避免了拷贝量最少的:重载复合赋值运算符的规范方式是什么?

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),这是不明确的。有人指出这是因为它是未定义的行为。

+0

'的std ::矢量&运算+ =(标准::矢量&LHS,常量性病::矢量&RHS)'适用于自赋值为好。 – 101010 2014-10-18 19:29:16

+0

@ 40two不,它不连接rhs。 – user4157389 2014-10-18 19:31:18

+0

真的吗? [LIVE DEMO](http://coliru.stacked-crooked.com/a/e1b7f483ae0e5723) – 101010 2014-10-18 19:32:24

回答

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

+1:这是正确的,并且实际上回答了问题。留下来做这个完美的唯一的事情就是提出一个关于'std :: vector :: insert'行为的标准报价。 – milleniumbug 2014-10-18 19:53:32

+0

那么,是否添加一个调用来保留count作为一种正确的技术? – 2014-10-18 19:55:45

+0

@MarcGlisse:请点击链接。 – 2014-10-18 19:58:07

0

作为一项政策,您不应将两个不同的std类型与它们之间的运算符重载。这可能是未定义的行为:标准不明确。

如果你想在std容器上使用操作符语法,我会推荐命名操作符。还有一点更加清楚,因为vector上的操作符可能是容器操作符或元素操作符,这就是缺省默认情况下缺失的原因。 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>作品与上面的代码。

+0

你不需要测试身份;请参阅我的答案中的'concat_in_place'代码片段。对于自引用和两个独立向量都是正确的,对于两个独立向量,也可能比原始代码更快。 – 2014-10-18 20:15:41

+1

@BenVoigt好点。而我在这个时候,我会写下我命名的操作迷你库的另一个迭代。它变得非常紧凑。虽然标签类型中的'static'方法很可爱,我想下次我会使用'plus(LHS,append_tag,RHS)'和'plus_assign(LHS,append_tag,RHS)类型的3个自变量函数)',因为这可以让人们为远离标签定义处的'append'添加新的含义。 – Yakk 2014-10-18 21:49:30

+0

@ BenVoigt是的,使用3参数'plus'而不是'static'方法更简洁。添加到帖子! – Yakk 2014-10-18 21:59:15