Cppreferenceの _std::transform
_ のコード例は次のとおりです。
_std::vector<std::size_t> ordinals;
std::transform(s.begin(), s.end(), std::back_inserter(ordinals),
[](unsigned char c) -> std::size_t { return c; });
_
しかし、それはまた言います:
_
std::transform
_は、_unary_op
_または_binary_op
_の順序どおりの適用を保証しません。関数をシーケンスに順番に適用するか、シーケンスの要素を変更する関数を適用するには、_std::for_each
_を使用します。
これはおそらく並列実装を可能にするためです。ただし、_std::transform
_の3番目のパラメーターは LegacyOutputIterator
であり、_++r
_に対して次の事後条件があります。
この操作の後、
r
はインクリメント可能である必要はなく、r
の以前の値のコピーは逆参照可能またはインクリメント可能である必要がなくなります。
したがって、出力の割り当てが順番に行われる必要があるように思えます。それらは単に_unary_op
_のアプリケーションが故障し、一時的な場所に保存されているが、出力に順番にコピーされる可能性があることを単に意味しているのですか?それはあなたがしたいことのようには聞こえません。
ほとんどのC++ライブラリは、実際には並列実行プログラムをまだ実装していませんが、Microsoftは実装しています。私はかなり this が関連するコードであることを確信しています、そして私はthinkそれが this populate()
function イテレータを出力のチャンクに記録します。LegacyOutputIterator
はそのコピーを増分することで無効化できるため、これは確かに有効なことではありません。
何が欠けていますか?
私は変換順序どおりに処理されることが保証されていますを信じています。 std::back_inserter_iterator
は [back.insert.iterator] によるoutputイテレータです(そのiterator_category
メンバー型はstd::output_iterator_tag
のエイリアスです)。
その結果、std::transform
には、result
パラメーターでメンバーoperator++
を呼び出すよりも、次の反復に進む方法について他のオプションなしがあります。
もちろん、これは、std::back_inserter_iterator
が使用されない可能性がある、実行ポリシーのないオーバーロードに対してのみ有効です(forwarding iteratorではありません)。
ところで、私はcppreferenceからの引用符で議論しません。そこにあるステートメントは、しばしば不正確または単純化されています。このような場合は、C++標準を確認することをお勧めします。ここで、std::transform
に関しては、操作の順序についての引用はありません。
したがって、私が見逃したのは、パラレルバージョンがLegacyForwardIterator
ではなく LegacyOutputIterator
sをとることです。 LegacyForwardIterator
canそれのコピーを無効にすることなくインクリメントされるため、これを使用して、順不同のパラレルstd::transform
を実装するのは簡単です。
std::transform
の非並列バージョンmustは順序どおりに実行されると思います。それについてcppreferenceが間違っているか、標準を実装する他の方法がないため、標準がこの要件を暗黙的に残している可能性があります。 (Shotgunは標準を調べて調べていません!)