考虑以下最小例子:
#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
的行为形成对比。
原因是因为在实现中,run-sum值的类型与源范围相对应:
semiregular_t<range_value_type_t<Rng>> sum_;
这是故意还是错误?
讨论:我看到在尝试获取有效返回类型时遇到的麻烦,因为转换函数使用源范围和结果范围作为参数并产生返回类型。下一个应用程序使用source-range-type和this返回类型来生成另一个(可能是不同的)返回类型,依此类推。
由此,原则上,一个是使用变换函数的结果类型重复链接源值类型。只有当结果类型“收敛”到可以转换为所有其他中间结果的特定类型时,此重复迭代才会产生一些可用的东西(在上面的示例中,此类型为double
,这是在第一个之后获得的调用转换函数。)
通过这种观察,可以提出一种解决方法:将二进制变换函数应用给定次数,并使用common_type
作为结果范围的值类型(如果发现收敛,则过早停止)。在最简单的情况下,迭代次数只有一次。如果这个迭代没有导致合理的东西,那么仍然可以求助于source-value-type(或编译器错误)。
为清楚起见,以下是上述示例的应用程序:
First iteration : f(int,int) -> yields "double"
Second iteration: f(int,double) -> yields "double"
Third iteration : f(int,double) -> yields "double"
在第三次迭代之后,模式收敛,因此停止并选择公共类型double
作为返回范围的value_type。
我不确定这种方法在所有理论情况下是否完全有效,但至少它在第一个例子中给出了两倍 - 我猜这是每个人都非常期待的。
答案 0 :(得分:5)
ranges::view::partial_sum
反映了std::partial_sum
的语义。如果您运行:
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
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; };
std::vector<double> rng;
std::partial_sum(v.begin(), v.end(), std::back_inserter(rng), f);
for(auto i : rng)
{
std::cout<<i<<" ";
}
}
你应该得到exactly the same output as from the program in the OP。与许多范围v3视图一样,此视图的作用是计算与标准算法计算的结果相同的结果序列,但这样做很懒散。
指定 std::partial_sum
对累加器进行操作,其类型与输入范围的值类型相同。 [partial.sum]/2说:
效果:对于非空范围,该函数会创建一个累加器
acc
,其类型为InputIterator
的值类型,使用*first
初始化它,并将结果赋给{ {1}}。对于*result
中的每个迭代器i
,[first + 1, last)
然后由acc
或acc = acc + *i
进行修改,结果将分配给acc = binary_op(acc, *i)
。< / p>
为了表现相同,*(result + (i - first))
还使用了一个累加器,其类型是输入范围的值类型。
对于OP,您可以使用ranges::view::partial_sum
作为输入范围的类型来实现所需的结果。使用range-v3,通过使用double
:
ranges::view::transform(ranges::convert_to<double>{})
which produces the desired output:
6 3.2 3.06 3.718 4.6154 5.58462