【发布时间】:2019-01-18 03:02:14
【问题描述】:
我正在阅读这篇关于在 Boost.Operator https://www.boost.org/doc/libs/1_69_0/libs/utility/operators.htm#symmetry 中实现对称运算符的说明,我怀疑它已经过时了。
讨论的重点是什么是一般实现operator+ 的最佳方式,如果一致的operator+= 可用。那里的结论是它是(曾经),
T operator+( const T& lhs, const T& rhs ){
T nrv( lhs ); nrv += rhs; return nrv;
}
因为当时一些编译器支持 NRVO,而不是 RVO。
现在, NRVO 是强制性的, 正在执行各种优化,这仍然是这种情况吗?
例如,在某些情况下现在可能有意义的其他版本是:
T operator+(T lhs, const T& rhs ){
T ret(std::move(lhs)); ret += rhs; return ret;
}
或
T operator+(T lhs, const T& rhs ){
lhs += rhs; return lhs;
}
给定一个具有构造函数、移动构造函数和合理operator+= 的类。例如:
#include<array>
#include<algorithm>
using element = double; // here double, but can be more complicated
using array = std::array<double, 9>; // here array, but can be more complicated
array& operator+=(array& a, array const& b){
std::transform(begin(a), end(a), begin(b), begin(a), [](auto&& x, auto&& y){return x + y;});
return a;
}
array& operator+=(array&& a, array const& b){
std::transform(begin(a), end(a), begin(b), begin(a), [](auto&& x, auto&& y){return x + std::move(y);});
return a;
}
实现对称operator+ 的最佳方法是什么?这是一组可能的代码
/*1*/ array sum(array const& a, array const& b){array tmp(a); tmp+=b; return tmp;} // need operator+= and copy-constructor
/*2*/ array sum(array const& a, array const& b){return array(a)+=b;} // needs operator+= && and copy-constructor
/*3*/ array sum(array a, array const& b){return std::move(a)+=b;} // needs operator+= && and can use move-constructor
/*4*/ array sum(array a, array const& b){array tmp(std::move(a)); tmp+=b; return tmp;} // needs operator+= and can use move-constructor
我在https://godbolt.org/z/2YPhcg 中进行了尝试,仅通过计算装配线的数量,所有其他条件都相同可能会告诉你什么是最好的实现。我得到了这些混合的结果:
| code | gcc -O2 | clang -O2 |
|:-----------|------------:|:------------:|
| /*1*/ | 33 lines | 64 lines |
| /*2*/ | 39 lines | 59 lines |
| /*3*/ | 33 lines | 62 lines |
| /*4*/ | 33 lines | 64 lines |
虽然/*3*/ 和/*4*/ 可以从sum(std::move(a), b) 甚至sum(sum(a, c), b) 形式的调用中受益。
那么T tmp(a); tmp+=b; return tmp; 仍然是实现operator+(T [const&], T const&) 的最佳方式吗?
看起来如果有一个移动构造函数和一个移动+=,还有其他可能性,但似乎只会在clang中产生更简单的组装。
【问题讨论】:
-
NRVO 不是强制性的
-
在粗体文本中,您专门询问
operator+的一个签名,而在前面的文本中,您允许不同的签名,请澄清 -
@M.M 好吧,我对行为感兴趣,而不是签名。