次の最小限の例を考えてみましょう。
#include <range/v3/all.hpp>
#include <iostream>
namespace rng = ranges::v3;
int main()
{
std::vector<int> v { 6, 2, 3, 4, 5, 6 };
auto f = [](auto a, auto b) { return a*0.3 + b*0.7;};
auto rng = v | rng::view::partial_sum(f);
for(auto i : rng)
{
std::cout<<i<<" ";
}
}
これは出力します
6 3 2 3 4 5
ここで倍数が表示されることを期待していましたが、結果は明らかに整数です。これは の動作とは対照的ですview::transform
。
この理由は、実装では、現在の合計値がソース範囲に対応する型を持っているためです。
semiregular_t<range_value_type_t<Rng>> sum_;
これは意図したものですか、それともバグですか?
ディスカッション: 変換関数がソース範囲と結果範囲の両方をパラメーターとして使用し、戻り値の型を生成するため、有効な戻り値の型を取得しようとすると問題が発生することがわかります。次のアプリケーションは、source-range-type とこの戻り値の型を使用して、別の (場合によっては異なる) 戻り値の型を生成します。
これにより、原則として、ソース値タイプを変換関数の結果タイプと繰り返し連鎖させます。この繰り返しの繰り返しにより、結果の型が他のすべての中間結果を変換できる特定の型に「収束」する場合にのみ使用可能なものが得られます (上記の例では、この型はdouble
であり、変換関数の最初の呼び出し後に既に取得されています)。 )。
この観察により、回避策を提案できます。バイナリ変換関数を指定された回数適用しcommon_type
、結果の範囲の as 値型を使用します (収束が見つかった場合は、途中で停止します)。最も単純なケースでは、反復回数は 1 回だけです。この繰り返しで妥当な結果が得られない場合でも、source-value-type (またはコンパイラ エラー) に頼ることができます。
明確にするために、上記の例のアプリケーションを次に示します。
First iteration : f(int,int) -> yields "double"
Second iteration: f(int,double) -> yields "double"
Third iteration : f(int,double) -> yields "double"
3 回目の反復の後、パターンは収束するので、停止しdouble
て返される範囲の value_type として common-type を選択します。
このアプローチがすべての理論的状況で完全に有効かどうかはわかりませんが、少なくとも最初の例では 2 倍になります。これは誰もが強く期待していることだと思います。