如何创建一个可以在流中下一个对象中调用特定函数的操纵器?

发布于 2025-01-18 08:52:20 字数 832 浏览 4 评论 0原文

假设我有一个如下的类:

class A
{
...private members
public:
void write_text(std::ostream& os); //writes members as text
void write_binary(std::ostream& os); //writes objects as binary
};

如何创建一个类似于 textbinary 的操纵器,具体取决于我可以调用适当的函数 write_text()write_binary() 写入文件流,如下所示:

std::ofstream file1("textfile.txt");
std::ofstream file2("binfile.bin");

A obj; // assume obj has data members set 
file1<<text<<obj; // here obj.write_text() should be invoked 
file2<<binary<<obj; // here obj.write_binary() should be invoked

我是否需要在流中存储诸如状态或变量之类的内容,如下所示 示例能够执行此操作或者是否存在更简单的方法?

Suppose I have a class as follows:

class A
{
...private members
public:
void write_text(std::ostream& os); //writes members as text
void write_binary(std::ostream& os); //writes objects as binary
};

How do I create a manipulator that like text and binary depending on which I can call appropriate function write_text() or write_binary() to write to filestream like so:

std::ofstream file1("textfile.txt");
std::ofstream file2("binfile.bin");

A obj; // assume obj has data members set 
file1<<text<<obj; // here obj.write_text() should be invoked 
file2<<binary<<obj; // here obj.write_binary() should be invoked

Do I need to store something like a state or a variable in the stream like in this example to be able to do this or is there a simpler way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

心的位置 2025-01-25 08:52:20

标准用法操纵输入&amp;的主要方式有两种主要方法。输出操作。

1。在流状态中存储值

您可以使用 <代码> std :: ios_base :: Xalloc()
这为您提供了longvoid*在每个流中的值,您可以使用 iword() / pword()

这与标准IO操纵器等标准的机制相同/code> , std :: boolalpha 使用。

请注意,如果您更改流状态,它将一直保持这种状态,直到您再次更改它,例如:

std::cout << std::hex << 16; // will be outputted in hexadecimal
std::cout << 12; // will still be outputted in hexadecimal

std::cout << std::dec << 16; // will be outputted in decimal
std::cout << 12; // still decimal

您可以为您的a类实现它:


class A {
public:
    void write_text(std::ostream& os) const {
        os << "TEXT";
    }

    void write_binary(std::ostream& os) const {
        os << "BINARY";
    }
};

// this gives us the unique index we need for pword() / iword()
inline int getAFormatIndex() {
    static int idx = std::ios_base::xalloc();
    return idx;
}

std::ostream& operator<<(std::ostream& os, A const& a) {
    std::ostream::sentry s{os};
    if(!s) return os;
    
    if(os.iword(getAFormatIndex()) == 0)
        a.write_text(os);
    else
        a.write_binary(os);

    return os;
}

struct text_t {};
struct binary_t {};

inline constexpr text_t text;
inline constexpr binary_t binary;

// change to text mode
std::ostream& operator<<(std::ostream& os, text_t const&) {
    os.iword(getAFormatIndex()) = 0;
    return os;
}

// change to binary mode
std::ostream& operator<<(std::ostream& os, binary_t const&) {
    os.iword(getAFormatIndex()) = 1;
    return os;
}
  • 运营商&lt;&lt; << /code> for a检查当前存储在流中的格式类型(文本为0,二进制1),并调用相应的方法
  • text> text&amp; 二进制是将流状态应用于流时更改流状态的IO操纵器。

示例用法:

A a;
std::cout << text << a;
std::cout << binary << a;
std::cout << a; // still in binary format

godbolt示例示例

2。包装器功能函数

,您还会在标准中遇到另一种类型的IO手工库是更改单个元素的输入 /输出的包装器。

其中的示例将为 std ::引用 std :: get_money std :: put_money 等...

这些功能仅更改单个操作的格式,与上述方法更改所有以下输入 /输出操作的格式相比。
示例:

std::cout << std::put_money(12.34); // will be formatted as monetary value
std::cout << 12.34; // normal double output
std::cout << std::quoted("foo"); // -> "foo"
std::cout << "foo"; // -> foo

您可以为您的a类实现它:


class A {
public:
    void write_text(std::ostream& os) const {
        os << "TEXT";
    }

    void write_binary(std::ostream& os) const {
        os << "BINARY";
    }
};

std::ostream& operator<<(std::ostream& os, A const& a) {
    std::ostream::sentry s{os};
    if(!s) return os;

    a.write_text(os);

    return os;
}

struct binary_impl { A const& a; };

std::ostream& operator<<(std::ostream& os, binary_impl const& b) {
    std::ostream::sentry s{os};
    if(!s) return os;

    b.a.write_binary(os);

    return os;
}

binary_impl binary(A const& a) {
    return { a };
}

// text is the default, so we need no wrapper
A const& text(A const& a) {
    return a;
}
  • 我们本质上使用包装对象(binary_impl),该对象实现了不同的ocerator&lt;&lt; 用于a对象。

示例用法:

A a;
std::cout << text(a);
std::cout << binary(a);
std::cout << a; // default is text format

godbolt示例示例


上面列出的方法只是标准库本身使用(因此可能可能是标准库本身最公认的)。

当然,您还可以为其创建自己的自定义方法,例如,使用返回将以特定方式序列化对象的对象的成员方法:

class A {
public:
    void write_text(std::ostream& os) const {
        os << "TEXT";
    }

    void write_binary(std::ostream& os) const {
        os << "BINARY";
    }

    struct as_text_t { A const& a; };
    struct as_binary_t { A const& a; };

    as_text_t as_text() const {
        return { *this };
    }

    as_binary_t as_binary() const {
        return { *this };
    }
};

std::ostream& operator<<(std::ostream& os, A::as_text_t const& el) {
    std::ostream::sentry s{os};
    if(!s) return os;

    el.a.write_text(os);

    return os;
}

std::ostream& operator<<(std::ostream& os, A::as_binary_t const& el) {
    std::ostream::sentry s{os};
    if(!s) return os;

    el.a.write_binary(os);

    return os;
}

<

A a;
std::cout << a.as_text();
std::cout << a.as_binary();

a href =“ https://godbolt.org/z/skxwcexan” rel =“ nofollow noreferrer”> godbolt示例

There are two primary ways the standard uses to manipulate input & output operations.

1. Storing values in the stream state

You can store formatting state within streams by using std::ios_base::xalloc().
This gives you a long and void* value in each stream that you can access with iword() / pword() .

This is the same mechanism that standard io manipulators like std::hex, std::boolalpha use.

Note that if you change the stream state it'll stay that way until you change it again, e.g.:

std::cout << std::hex << 16; // will be outputted in hexadecimal
std::cout << 12; // will still be outputted in hexadecimal

std::cout << std::dec << 16; // will be outputted in decimal
std::cout << 12; // still decimal

You could e.g. implement it like this for your A class:


class A {
public:
    void write_text(std::ostream& os) const {
        os << "TEXT";
    }

    void write_binary(std::ostream& os) const {
        os << "BINARY";
    }
};

// this gives us the unique index we need for pword() / iword()
inline int getAFormatIndex() {
    static int idx = std::ios_base::xalloc();
    return idx;
}

std::ostream& operator<<(std::ostream& os, A const& a) {
    std::ostream::sentry s{os};
    if(!s) return os;
    
    if(os.iword(getAFormatIndex()) == 0)
        a.write_text(os);
    else
        a.write_binary(os);

    return os;
}

struct text_t {};
struct binary_t {};

inline constexpr text_t text;
inline constexpr binary_t binary;

// change to text mode
std::ostream& operator<<(std::ostream& os, text_t const&) {
    os.iword(getAFormatIndex()) = 0;
    return os;
}

// change to binary mode
std::ostream& operator<<(std::ostream& os, binary_t const&) {
    os.iword(getAFormatIndex()) = 1;
    return os;
}
  • The operator<< for A checks which format type is currently stored in the stream (0 for text, 1 for binary) and calls the corresponding method
  • text & binary are the io manipulators that change the stream state when applied to a stream.

Example Usage:

A a;
std::cout << text << a;
std::cout << binary << a;
std::cout << a; // still in binary format

godbolt example

2. Wrapper function

Another kind of io manipulators you'll also encounter in the standard library are wrappers that change the input / output of a single element.

Examples of this would be std::quoted, std::get_money, std::put_money, etc...

Those functions only change the format for a single operation, in contrast to the above method that changes the format of all following input / output operations.
Example:

std::cout << std::put_money(12.34); // will be formatted as monetary value
std::cout << 12.34; // normal double output
std::cout << std::quoted("foo"); // -> "foo"
std::cout << "foo"; // -> foo

You could e.g. implement it like this for your A class:


class A {
public:
    void write_text(std::ostream& os) const {
        os << "TEXT";
    }

    void write_binary(std::ostream& os) const {
        os << "BINARY";
    }
};

std::ostream& operator<<(std::ostream& os, A const& a) {
    std::ostream::sentry s{os};
    if(!s) return os;

    a.write_text(os);

    return os;
}

struct binary_impl { A const& a; };

std::ostream& operator<<(std::ostream& os, binary_impl const& b) {
    std::ostream::sentry s{os};
    if(!s) return os;

    b.a.write_binary(os);

    return os;
}

binary_impl binary(A const& a) {
    return { a };
}

// text is the default, so we need no wrapper
A const& text(A const& a) {
    return a;
}
  • We essentially use a wrapper object (binary_impl) that implements a different operator<< for A objects.

Example Usage:

A a;
std::cout << text(a);
std::cout << binary(a);
std::cout << a; // default is text format

godbolt example


The methods listed above are only the ones the standard library itself uses (and therefore probably the most recognized ones).

You can of course also create your own custom method for it, e.g. by using member methods that return objects that will serialize the object in a specific way:

class A {
public:
    void write_text(std::ostream& os) const {
        os << "TEXT";
    }

    void write_binary(std::ostream& os) const {
        os << "BINARY";
    }

    struct as_text_t { A const& a; };
    struct as_binary_t { A const& a; };

    as_text_t as_text() const {
        return { *this };
    }

    as_binary_t as_binary() const {
        return { *this };
    }
};

std::ostream& operator<<(std::ostream& os, A::as_text_t const& el) {
    std::ostream::sentry s{os};
    if(!s) return os;

    el.a.write_text(os);

    return os;
}

std::ostream& operator<<(std::ostream& os, A::as_binary_t const& el) {
    std::ostream::sentry s{os};
    if(!s) return os;

    el.a.write_binary(os);

    return os;
}

Usage:

A a;
std::cout << a.as_text();
std::cout << a.as_binary();

godbolt example

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文