You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++20中使用partial_sum处理不同类型的输出容器?

关于C++20 partial_sum中输入输出迭代器类型不匹配的问题

问题背景

我正在研究C++20的<numeric>头文件中的partial_sum。根据文档说明,输出迭代器OutputIt的类型可以与输入迭代器InputIt不同。

我定义了如下结构体:

typedef struct score_card {
    std::string name;
    int score;

} score_card;

希望将vector<score_card>中的int类型score字段累积到vector<int>中。文档中的C++20声明明确允许输出迭代器与输入迭代器类型不同:

template< class InputIt, class OutputIt, class BinaryOperation >
constexpr OutputIt partial_sum( InputIt first, InputIt last, OutputIt d_first,
                                BinaryOperation op );

尝试的实现代码

void partial_sum_score()
{
    std::vector<score_card> data{
        {"Bob", 2},
        {"Mallory", 1},
        {"Alice", 2},
        {"carol", 0}
    };

    std::vector<int> data_partial_sum{
        0, 0, 0, 0
    };

    auto accumilate_scores = [](score_card first, score_card second) {return first.score + second.score; };

    std::partial_sum(data.begin(), data.end(), data_partial_sum.begin(), accumilate_scores);
}

编译错误

在Microsoft VS 2022中出现以下错误:

Error   C2440   '=': cannot convert from 'score_card' to 'int'  ******* C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.30.30705\include\numeric  253 
Error   C2679   binary '=': no operator found which takes a right-hand operand of type 'int' (or there is no acceptable conversion) ******  C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.30.30705\include\numeric  260 

错误逻辑上成立:第一个输出元素是int类型,但第一个输入元素是score_card类型。查看<numeric>头文件中的实现,发现代码未引用_OutIt的类型:

template <class _InIt, class _OutIt, class _BinOp>
_CONSTEXPR20 _OutIt partial_sum(const _InIt _First, const _InIt _Last, _OutIt _Dest, _BinOp _Reduce_op) {
    // compute partial noncommutative and nonassociative reductions into _Dest, using _Reduce_op
    _Adl_verify_range(_First, _Last);
    auto _UFirst      = _Get_unwrapped(_First);
    const auto _ULast = _Get_unwrapped(_Last);
    auto _UDest       = _Get_unwrapped_n(_Dest, _Idl_distance<_InIt>(_UFirst, _ULast));

    if (_UFirst != _ULast) {
        _Iter_value_t<_InIt> _Val(*_UFirst);
        for (;;) {
            *_UDest = _Val;
            ++_UDest;
            ++_UFirst;
            if (_UFirst == _ULast) {
                break;
            }
#if _HAS_CXX20
            _Val = _Reduce_op(_STD move(_Val), *_UFirst);
#else // ^^^ _HAS_CXX20 ^^^ // vvv !_HAS_CXX20 vvv
            _Val      = _Reduce_op(_Val, *_UFirst);
#endif // _HAS_CXX20
        }
    }

    _Seek_wrapped(_Dest, _UDest);
    return _Dest;
}

疑问

我忽略了什么?这种需求是否可行?如果不可行,为何允许输出迭代器与输入迭代器类型不同?(可选)输出目标容器大小不匹配时(比如data_partial_sum大小为1)该如何处理?


问题分析与解决方案

1. 核心问题所在

partial_sum的设计有两个关键约束你没注意到:

  • 累加器_Val的默认类型是输入迭代器的值类型(也就是score_card),它需要直接赋值给输出迭代器指向的类型(int),这一步类型不兼容导致第一个错误。
  • 你的二元操作返回int,但要赋值给score_card类型的_Val,类型不匹配导致第二个错误。

2. 需求的可行实现方式

有两种可靠的方式实现你的需求:

方式一:用视图转换输入元素类型(C++20推荐)

通过std::views::transform将score_card转换为int类型的视图,再执行partial_sum:

#include <numeric>
#include <vector>
#include <string>
#include <ranges>

typedef struct score_card {
    std::string name;
    int score;

} score_card;

void partial_sum_score()
{
    std::vector<score_card> data{
        {"Bob", 2},
        {"Mallory", 1},
        {"Alice", 2},
        {"carol", 0}
    };

    std::vector<int> data_partial_sum(data.size());

    // 生成仅包含score的视图
    auto score_view = data | std::views::transform([](const score_card& sc) { return sc.score; });
    
    std::partial_sum(score_view.begin(), score_view.end(), data_partial_sum.begin());
}

如果需要自定义累加逻辑,直接替换默认的加法操作即可。

方式二:手动适配二元操作的类型

如果不想用视图,可以手动处理第一个元素的类型转换,并让二元操作的输入输出匹配输出类型:

void partial_sum_score()
{
    std::vector<score_card> data{
        {"Bob", 2},
        {"Mallory", 1},
        {"Alice", 2},
        {"carol", 0}
    };

    std::vector<int> data_partial_sum(data.size());

    if (data.empty()) return;

    // 第一个元素直接赋值score
    data_partial_sum[0] = data[0].score;
    // 从第二个元素开始累加,累加器为int类型
    std::partial_sum(std::next(data.begin()), data.end(), std::next(data_partial_sum.begin()),
        [](int current_sum, const score_card& next_sc) {
            return current_sum + next_sc.score;
        });
}

3. 为什么允许输出迭代器与输入迭代器类型不同?

这个设计是为了支持输入输出类型兼容的转换场景,常见的例子比如:

  • 输入int,输出long long,避免累加溢出:
    std::vector<int> nums{1,2,3,4};
    std::vector<long long> sums(nums.size());
    std::partial_sum(nums.begin(), nums.end(), sums.begin());
    

这种场景下,输入类型(int)可以隐式转换为输出类型(long long),累加器的赋值和二元操作的结果都能兼容输出类型。

4. 输出容器大小不匹配的处理

  • 如果输出容器大小小于输入容器:会触发未定义行为,因为partial_sum会写入超出容器范围的元素。解决办法是提前将输出容器resize到输入容器的大小,或者使用插入迭代器:
    std::vector<int> data_partial_sum;
    auto score_view = data | std::views::transform([](const score_card& sc) { return sc.score; });
    std::partial_sum(score_view.begin(), score_view.end(), std::back_inserter(data_partial_sum));
    
    std::back_inserter会自动向容器添加元素,无需提前指定大小。
  • 如果输出容器大小大于输入容器:多余的元素会保持初始值,不会被修改。

内容的提问来源于stack exchange,提问作者Ziad AbouWasa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 04:20:21