# std::ranges::views::join, std::ranges::join_view

< cpp‎ | ranges

定义于头文件 `<ranges>` |  |
template< ranges::input_range V > requires ranges::view<V> && ranges::input_range<ranges::range_reference_t<V>> class join_view : public ranges::view_interface<join_view<V>> | (1) | (C++20 起)
namespace views { inline constexpr /* unspecified */ join = /* unspecified */; } | (2) | (C++20 起)

1) 表示由从拉平范围的视图获得的序列组成的 `view` 。
2) 范围适配器对象。对于任何适合的子表达式 e 表达式 views::join(e) 表达式等价于 join_view<views::all_t<decltype((e))>>{e} 。

### 表达式等价

表达式 e 表达式等价于表达式 f ，若 e 与 f 拥有相同效果，均为潜在抛出或均非潜在抛出（即 noexcept(e) == noexcept(f) ），且均为常量子表达式或均非常量子表达式。

### 成员函数

(构造函数) (C++20) | 构造 `join_view` (公开成员函数)
base (C++20) | 返回底层（适配的）视图的副本 (公开成员函数)
begin (C++20) | 返回指向起始的迭代器 (公开成员函数)
end (C++20) | 返回指向末尾的迭代器或哨位 (公开成员函数)
##### 继承自 std::ranges::view_interface
empty (C++20) | 返回视图是否为空。若视图满足 `forward_range` 则提供。 (`std::ranges::view_interface<D>` 的公开成员函数)
operator bool (C++20) | 返回派生视图是否为非空。若 ranges::empty 可应用于它则提供。 (`std::ranges::view_interface<D>` 的公开成员函数)
front (C++20) | 返回派生视图中的首元素。若视图满足 `forward_range` 则提供。 (`std::ranges::view_interface<D>` 的公开成员函数)
back (C++20) | 返回派生视图中的末元素。若视图满足 `bidirectional_range` 与 `common_range` 则提供。 (`std::ranges::view_interface<D>` 的公开成员函数)

### 推导指引

### 嵌套类

iterator (C++20) | 迭代器类型 (仅用于阐释的成员类模板)
sentinel (C++20) | 哨位类型 (仅用于阐释的成员类模板)

### 注解

在接纳 P2328R1 前，内层范围类型（ ranges::range_reference_t<V> ）不能为容器类型（但能为容器的引用）。例如不允许接合 std::string 纯右值的 `transform_view` 。

    struct Person { int age; std::string name; };
    auto f(std::vector<Person>& v) {
     // return v | std::views::transform([](auto& p) { return p.name; })
     //          | std::views::join; // P2328R1 前错误
        return v | std::views::transform([](auto& p) -> std::string& { return p.name; })
                 | std::views::join; // OK
    }

### 示例

    #include <iostream>
    #include <ranges>
    #include <string_view>
    #include <vector>

    int main()
    {
        using namespace std::literals;
        const auto bits = { "https:"sv, "//"sv, "cppreference"sv, "."sv, "com"sv };
        for (char const c : bits | std::views::join) std::cout << c;
        std::cout << '\n';

        const std::vector<std::vector<int>> v{ {1,2}, {3,4,5}, {6}, {7,8,9} };
        auto jv = std::ranges::join_view(v);
        for (int const e : jv) std::cout << e << ' ';
        std::cout << '\n';
    }

输出：

    https://cppreference.com
    1 2 3 4 5 6 7 8 9

### 缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

DR | 应用于 | 出版时的行为 | 正确行为
--- | --- | --- | ---
LWG 3474 | C++20 | views::join(e) 在 e 为 `join_view` 时返回 e 的副本 | 返回嵌套的 `join_view`
P2328R1 | C++20 | `join_view` 无法接合非视图 `range` 纯右值 | 使得可接合

### 参阅

ranges::split_view views::split (C++20) | 用某个分隔符切割另一 `view` 所获得的子范围的 `view` (类模板) (范围适配器对象)
ranges::lazy_split_view views::lazy_split (C++20) | 用某个分隔符切割另一 `view` 所获得的子范围的 `view` (类模板) (范围适配器对象)