gpt4 book ai didi

c++ - 粘性自定义流操纵器

转载 作者:IT老高 更新时间:2023-10-28 23:15:12 27 4
gpt4 key购买 nike

如何实现我自己的自定义流操纵器以使其具有粘性。例如,我想将整数转换为二进制,这样:

cout << "decimal of 4: " <<  4 
<< "\ndecimal of 4: " << 4
<< binary << "\nbinary of 4: " << 4
<< "\nbinary of 4: " << 4
<< nobinary << "\ndecimal of 4: " << 4
<< "\ndecimal of 4: " << 4 << endl;

会返回:

decimal of 4: 4
decimal of 4: 4
binary of 4: 100
binary of 4: 100
decimal of 4: 4
decimal of 4: 4

最佳答案

做整个事情有点复杂。为了使其易于理解,我将从基本内容开始:对用户定义的类型使用自定义格式标志。整数的自定义格式如下所示。

IOStream 类 [间接] 派生自 std::ios_base它为数据提供了两个存储:std::ios_base::iword()std::ios_base::pword()对于 intvoid* , 分别。维护使用 std::ios_base::pword() 存储的分配内存很重要,幸运的是,对于这个相对简单的用例不需要。要使用这些都返回非 const 的函数引用相应类型,通常使用 std::ios_base::xalloc() 分配索引一次在您的程序中,并在您需要访问自定义格式标志时使用它。当您使用 iword() 访问值时或 pword()最初它将被零初始化。总而言之,这里有一个小程序演示了这一点:

#include <iostream>

static int const index = std::ios_base::xalloc();

std::ostream& custom(std::ostream& stream) {
stream.iword(index) = 1;
return stream;
}

std::ostream& nocustom(std::ostream& stream) {
stream.iword(index) = 0;
return stream;
}

struct mytype {};
std::ostream& operator<< (std::ostream& out, mytype const&) {
return out << "custom-flag=" << out.iword(index);
}

int main()
{
std::cout << mytype() << '\n';
std::cout << custom;
std::cout << mytype() << '\n';
std::cout << nocustom;
std::cout << mytype() << '\n';
}

现在,int喜欢 4不是用户定义的类型,并且已经为这些定义了输出运算符。幸运的是,您可以自定义使用构面格式化整数的方式,更具体地说,使用 std::num_put<char> .现在,要做到这一点,您需要执行多个步骤:

  1. std::num_put<char> 派生一个类并覆盖 do_put()您想给予特殊行为的成员。
  2. 创建一个 std::locale使用新创建的构面的对象。
  3. std::ios_base::imbue()带有新 std::locale 的流.

为了让用户感觉更好,您可能想变出一个新的 std::locale与合适的std::num_put<char>使用机械手时的刻面。但是,在这样做之前,让我们先创建一个合适的方面:

#include <bitset>
#include <iostream>
#include <limits>
#include <locale>

static int const index = std::ios_base::xalloc();

class num_put
: public std::num_put<char>
{
protected:
iter_type do_put(iter_type to,
std::ios_base& fmt,
char_type fill,
long v) const
{
if (!fmt.iword(index)) {
return std::num_put<char>::do_put(to, fmt, fill, v);
}
else {
std::bitset<std::numeric_limits<long>::digits> bits(v);
size_t i(bits.size());
while (1u < i && !bits[i - 1]) {
--i;
}
for (; 0u < i; --i, ++to) {
*to = bits[i - 1]? '1': '0';
}
return to;
}
}
#if 0
// These might need to be added, too:
iter_type do_put(iter_type, std::ios_base&, char_type,
long long) const;
iter_type do_put(iter_type, std::ios_base&, char_type,
unsigned long) const;
iter_type do_put(iter_type, std::ios_base&, char_type,
unsigned long long) const;
#endif
};

std::ostream& custom(std::ostream& stream) {
stream.iword(index) = 1;
return stream;
}

std::ostream& nocustom(std::ostream& stream) {
stream.iword(index) = 0;
return stream;
}

int main()
{
std::locale loc(std::locale(), new num_put);
std::cout.imbue(loc);
std::cout << 13 << '\n';
std::cout << custom;
std::cout << 13 << '\n';
std::cout << nocustom;
std::cout << 13 << '\n';
}

有点难看的是必须要imbue()定制std::locale使用 custom机械手。为了摆脱这个问题,我们可以确保自定义 facet 安装在使用过的 std::locale 中。如果不是,则在设置标志时安装它:

std::ostream& custom(std::ostream& stream) {
if (!stream.iword(index)
&& 0 == dynamic_cast<num_put const*>(
&std::use_facet<std::num_put<char> >(stream.getloc()))) {
stream.imbue(std::locale(stream.getloc(), new num_put));
}
stream.iword(index) = 1;
return stream;
}

现在剩下的就是覆盖不同的 do_put()成员与各种unsigned 正常工作类型和 long long但这留作练习。

关于c++ - 粘性自定义流操纵器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13335193/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com