暂时覆盖输出流行为

Temporarily override output stream behavior

本文关键字:流行 输出流 输出 覆盖      更新时间:2023-10-16

假设我有一个字符向量(或者只是一个迭代器对),我想将其打印到ostream。现在,我不仅想要打印它 - 我希望它具有特定类型的间距,我想要字符值的不同表示形式,而不仅仅是将它们脱口而出到终端(例如,如果可打印,则字符和转义的 2 位或十六进制代码。

现在我不想编写自己的自定义代码超出最低限度 - 即只是一点胶水和

void foo(ostream& os, char c) {
    os << c << ' ' << as_hex(c);
}

(这就像运算符的自定义重载<<没有返回。

我不想在 vecotr 上循环,对于每个角色手动调用 abve,我希望它的行为和看起来好像我只是在暂时更改后者的属性后将我的向量传输到我的输出流。但有时我希望流恢复正常行为,即使对于相同的向量也是如此。

这可以合理/习惯地完成吗?

我假设您了解运算符重载,您的主要问题是如何告诉运算符使用哪个格式选项,即如何在流中存储任意信息。

任何派生自std::ios_base(所有标准流类)的方法都有.iword()方法,该方法从某些内部存储.pword()返回对long的引用,并返回对void*的引用。这些调用的唯一索引可以通过调用std::ios_base::xalloc()来获取

使用流存储更改输出操作行为的示例:

#include <iostream>
#include <vector>
const int vprint_index = std::ios_base::xalloc();
std::ostream& operator<<(std::ostream& out, std::vector<char> vec)
{
    if (out.iword(vprint_index) == 0) {
        for(char c: vec)
            out << c;
        return out;
    }
    out.iword(vprint_index) = 0;
    out << '{';
    bool first = true;
    for(char c: vec) {
        if(!first)
            out << ", ";
        first = false;
        out << c;
    }
    return out << '}';
}
int main()
{
    std::vector<char> vector {'f', 'o', 'o'};
    std::cout << vector << 'n';
    std::cout.iword(vprint_index) = 1;
    std::cout << vector << 'n';
    std::cout << vector << 'n';
}

噗��
{f, o, o}
噗噗��

对于暂时的重载,我认为做一些像 iomanip 这样的事情会很好。这将允许做类似的事情

int main() 
{ 
    std::vector<char> v{'a', 'b'}; 
    /* v should be printed using foo_vector_print, perhaps
    *    next invocation should use a different format. */
    std::cout << foo_vector_print() << v << std::endl; 
}   

这个想法是有这样一种形式:

 stream << manip << vector;

哪里

  • stream << manip将返回存储对流的引用的类的对象。
  • ... << vector将使用特定格式打印,然后返回对原始流的引用。

以下程序演示如何执行此操作:

#include <iostream>
#include <vector>

namespace detail
{
// A dummy class in detail namespace, simply records the original ostream object.
struct foo_vector_printer_imp
{
    std::ostream *m_os;
};
};

// This particular implementation simply prints out the vectors size.
std::ostream &operator<<(detail::foo_vector_printer_imp imp, const std::vector<char> &v)
{
    *imp.m_os << v.size();
    return *imp.m_os;
}

struct foo_vector_print{};

/* The result of piping a foo_vector_print into an ostream, 
*    is a foo_vector_printer_imp object recording the ostream */
detail::foo_vector_printer_imp operator<<(std::ostream &os, const foo_vector_print &)
{
    detail::foo_vector_printer_imp imp;
    imp.m_os = &os;
    return imp;
}

int main() 
{ 
    std::vector<char> v{'a', 'b'}; 
    std::cout << foo_vector_print() << v << std::endl; 
}   

好吧,你必须在某个地方编写你的自定义代码。矢量的内容不会自行写入std::ostream

从外观上看,您实际上是在问如何使用<<运算符在std::vector<char>上进行操作。以下示例应帮助您入门:

#include <iostream>
#include <vector>
std::ostream &operator<<(std::ostream &o, const std::vector<char> &v)
{
    // Fill in the blanks here.
    return o;
}
// Example:
int main()
{
    std::vector<char> v;
    std::cout << v;
    return 0;
}