流输出迭代器

题目描述

类比 std::ostream_iterator,补全 OstreamIterator 类模板的定义。即向 OstreamIterator 所指向的内容写入时,将内容输出到流中。

关于输入

关于输出

见样例输出

注意事项

C++17 标准要求迭代器提供五个类型别名,而且可复制构造、可复制赋值。因此我们在预设代码中提供了这些声明。

但是,如果你尝试在迭代器中添加引用成员(如 std::ostream& os),那么预置的复制赋值会被删除,从而在部分编译器/标准库实现中给出错误。(具体而言,引用成员无法如同复制构造那样复制赋值“重新绑定”,因此不提供预置复制赋值。)

对于这道题来说,使用指针成员是最标准的做法。

参考答案

#include <algorithm>
#include <iostream>
#include <vector>
#include <sstream>
#include <cassert>

template <typename T>
class OstreamIterator {
public:
    // C++17 规定的迭代器必须定义的类型别名
    // C++20 只需 value_type 和 difference_type
    using value_type = T;
    using reference = T&;
    using pointer = T*;
    using difference_type = std::ptrdiff_t;
    using iterator_category = std::output_iterator_tag;
    OstreamIterator(const OstreamIterator&) = default;
    OstreamIterator& operator=(const OstreamIterator&) = default;

private:
   std::ostream* os;
   
public:
    OstreamIterator(std::ostream& os) : os{&os} {}
    OstreamIterator& operator=(const T& val) {
        *os << val;
        return *this;
    }
    OstreamIterator& operator*() {
        return *this;
    }
    OstreamIterator& operator++() {
        return *this;
    }
    OstreamIterator& operator++(int) {
        return *this;
    }
};

int main() {
    std::string strArr[]{"Creeper", "? ", "Aw", " ", "man"};
    std::copy(std::begin(strArr), std::end(strArr), OstreamIterator<std::string>(std::cout));

    // 输出到 std::string 的流
    std::stringstream ss;
    std::vector<int> intVec{1, 2, 3, 4, 5};
    std::copy(intVec.begin(), intVec.end(), OstreamIterator<int>(ss));
    assert(ss.str() == "12345");
}