使用 C++20 范围展平嵌套 for 循环

Flatten nested for loops with C++20 ranges

有时我需要“双重 for 循环”,因为除了将第一个循环变量传递给内部 for 循环外,我在外部 for 循环中什么也没做,我想知道它是否可以用 C++20 范围优雅地完成。

我想“展平”的嵌套 for 循环示例。

struct Person{
    std::string name = "Bjarne";
};

std::vector persons{Person{}, Person{}};

int main() {
    for (const auto& person: persons) {
        for (const auto& ch: person.name) {
            std::cout << ch << std::endl;
        }
    }
}

我能想到的最好is:

std::ranges::for_each(persons | std::views::transform(&Person::name) | std::views::join, [](const char& ch){
    std::cout << ch << std::endl;
});

但是不知道有没有更简单的方法

是的,你的建议是正确的。除了它仍然可以是一个 range-based for 语句,你不必切换到一个算法:

for (const auto& ch : persons
                    | std::views::transform(&Person::name)
                    | std::views::join)
{
    // ... 
}

大多数语言使用名称 map 而不是 transform,使用 flatten 而不是 join(事实上,您的问题标题询问的是扁平化)。然后通常将这两者与一个名为 flat_map 的新算法放在一起,该算法将这两件事结合在一起。

我们也能做到:

inline constexpr auto flat_map = [](auto f){
    return std::views::transform(f) | std::views::join;
};

for (const auto& ch : persons | flat_map(&Person::name))
{
    // ... 
}

尽管在 C++ 中我想这会被称为 transform_join?嗯。 flat_map一路走来。


Pro-tip: use fmt::print 打印范围,写得少,而且已经格式化了。