1

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

当時、一部のコンパイラは RVO ではなく NRVO をサポートしていたためです。

現在、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 |

while/*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 でより単純なアセンブリを生成するように見えるだけです。

4

1 に答える 1