Consider the following minimal example:
#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<<" ";
}
}
This outputs
6 3 2 3 4 5
I would have expected to see double numbers here, but the result are obvisouly integers. This is in contrast to the behavior of view::transform
.
The reason for this is because in the implementation, the running-sum value has a type that corresponds to the source range:
semiregular_t<range_value_type_t<Rng>> sum_;
Is this intended or a bug?
Discussion: I see the trouble one is running into when trying to get a valid return type, as as the transformation function is using both the source range and the result range as parameters and produces a return type. The next application uses the source-range-type and this return type to produce another (possibly different) return type, and so on.
By this, in principle, one is repeatedly chaining the source-value-type with the result types of the transformation function. This repeated iteration yields something usable only if the result type "converges" to a specific type to which all other intermediate results can be converted to (in the example above, this type is double
, which is obtained already after the first call of the transformation function).
With this observation one could propose a workaround: apply the binary transformation function a given number of times and the use the common_type
as value type of the resulting range (if one finds a convergence, prematurely stop). In the simplest case, the number of iterations is just one. If this iteration does not lead to something reasonable, one can still resort to the source-value-type (or a compiler error).
To make it clear, here is the application for the example above:
First iteration : f(int,int) -> yields "double"
Second iteration: f(int,double) -> yields "double"
Third iteration : f(int,double) -> yields "double"
After the third iteration the pattern converges, so stop and choose the common-type double
as the value_type of the returned range.
I'm not sure whether this approach is completely valid in all theoretical circumstances, but at least it gives a double in the first example -- which I guess is what everyone is strongly expecting.