粘性自定义流操纵器
Sticky custom stream manipulator
如何实现自己的自定义流操纵器,以使其粘稠。例如,我想将整数转换为二进制,以便:
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
派生[间接],该类别分别为int
S和void*
提供了两个数据:std::ios_base::iword()
和std::ios_base::pword()
。维持使用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';
}
现在,像4
这样的int
不是用户定义类型,并且已经为这些定义了输出操作员。幸运的是,您可以自定义使用facets格式化整数的方式,更具体地使用std::num_put<char>
。现在,要这样做,您需要执行多个步骤:
- 从
std::num_put<char>
得出一个类,并覆盖您要提供专业行为的do_put()
成员。 - 使用新创建的Facet创建
std::locale
对象。 -
std::ios_base::imbue()
带有新std::locale
的流。
为了使用户变得更好,您可能需要在使用操纵器时使用合适的std::num_put<char>
刻面汇总新的std::locale
。但是,在此之前,让我们从创建合适的方面开始:
#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
操纵器。为了摆脱此功能,我们只能确保将自定义方面安装在使用的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++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 如何将点击的信号和插槽添加到qt中的自定义按钮中
- C++自定义比较函数
- 如何比较自定义类的std::变体
- std::设置自定义比较器
- 如何正确实现和访问运算符的各种自定义枚举器
- flutter:即使shouldRepaint()返回true,自定义画家也不会重新绘制
- 自定义先决条件对移动分配运算符有效吗
- 使用VS Code和CMake Tools运行自定义命令
- C++自定义流操纵器,用于更改流上的下一个字符串
- 如何使用自定义流操纵器在类实例中保存数据
- 如何键入用于const对象的自定义io操纵器
- 如何实现接受参数的自定义流操纵器?
- 如何从类中返回自定义数组项目并操纵其属性?C
- 粘性自定义流操纵器
- 类的自定义操纵器
- C++十六进制整数的自定义 I/O 操纵器
- Android:如何将自定义对象的数组列表传递给c++代码,并使用JNI在Java代码中获得这些对象的操纵数组列表
- 自定义流操纵器,用于在任何基中流式传输整数
- 如何实现自动添加分隔符的自定义粘性操纵器