std::transform 应用于 Sequence 元素的数据成员

std::transform applied to data member of sequence's element

提问人:Soup Endless 提问时间:11/23/2022 最后编辑:Jarod42Soup Endless 更新时间:11/23/2022 访问量:120

问:

请帮我找到一种优雅的方式来使用或类似的算法重写此代码片段:std::transform

for (auto& warning : warnings)
{
    NormalizePath(warning.path, GetParsedPathLength(warning.path), longestPathLength);
};

其中 是 .warningstruct

这是我想出的:

std::transform(begin(warnings), end(warnings), begin(warnings),
    [longestPathLength](auto& warning)
    {
        NormalizePath(warning.path, GetParsedPathLength(warning.path), longestPathLength);
        return warning;
    });

但它需要完整数据结构的副本。有没有办法创建仅包含成员的原始序列的可修改视图?所以转换只能被重写,接受并返回修改。最后,所有更改都应该影响原始序列。pathpathwarnings

C++ 算法 std

评论

3赞 Sam Varshavchik 11/23/2022
“优雅”主要是意见问题。在我看来,代码的原始版本看起来非常优雅。
2赞 Revolver_Ocelot 11/23/2022
我的意思是,你可以将 ranged-for 包装到for_each算法中,但你为什么要这样做呢?原始代码足够清晰简洁。
0赞 Nelfeal 11/23/2022
“需要完整数据结构的副本” - 怎么会这样?您是通过引用传递的。
1赞 jls28 11/23/2022
可以避免复制:只需更改:[longestPathLength](auto& warning) -> auto &
1赞 Nelfeal 11/23/2022
@SoupEndless 很公平,但我认为你很困惑。如果您通过引用获取,则无需返回该 lambda 中的任何内容。所以你不需要,而是.但是,这只是一种更复杂的方法来编写原始循环。warningstd::transformstd::for_each

答:

1赞 Jarod42 11/23/2022 #1

使用范围 (C++20),您可以“缩短”第一个版本:

for (auto& path : warnings | std::views::transform(&Warning::path))
{
    NormalizePath(path, GetParsedPathLength(path), longestPathLength);
}

评论

0赞 Soup Endless 11/26/2022
这真是太美了。
0赞 Soup Endless 11/26/2022
你能分享一下你学到的资源吗?我无法在任何地方看到这种用法。views::transform
1赞 Jarod42 11/26/2022
std::function可以执行该语法,std::invoke 允许更广泛地使用它。
1赞 Ranoiaetep 11/23/2022 #2

您可以通过 lambda 和函数绑定创建一些临时函数:

auto func = [](int size, auto& str){ 
    NormalizePath(str, GetParsedPathLength(str), size); 
};

然后使用以下命令调用该函数:ranges::for_each

std::ranges::for_each(
    warnings, std::bind_front(func, longestPathLength), &warning::path
);

演示