“显而易见”的解决方案是使用操纵器安装一个自定义std::num_put<char>
方面,该方面只是根据需要格式化int
s。
上面的陈述可能有点神秘,尽管它完全描述了解决方案。下面是实际实现逻辑的代码。第一个成分是一个特殊的std::num_put<char>
方面,它只是一个派生std::num_put<char>
并覆盖它的一个virtual
函数的类。used facet 是一个过滤 facet,它查看与流一起存储的标志(使用iword()
)以确定它是否应该改变行为。这是代码:
class num_put
: public std::num_put<char>
{
std::locale loc_;
static int index() {
static int rc(std::ios_base::xalloc());
return rc;
}
friend std::ostream& twodigits(std::ostream&);
friend std::ostream& notwodigits(std::ostream&);
public:
num_put(std::locale loc): loc_(loc) {}
iter_type do_put(iter_type to, std::ios_base& fmt,
char fill, long value) const {
if (fmt.iword(index())) {
fmt.width(2);
return std::use_facet<std::num_put<char> >(this->loc_)
.put(to, fmt, '0', value);
}
else {
return std::use_facet<std::num_put<char> >(this->loc_)
.put(to, fmt, fill, value);
}
}
};
主要部分是do_put()
决定如何格式化值的成员函数:如果 in 中的标志fmt.iword(index())
非零,它将宽度设置为2
并使用填充字符调用格式化函数0
。无论如何,宽度都会被重置,并且填充字符不会与流一起存储,即不需要任何清理。
通常,代码可能存在于单独的翻译单元中,并且不会在标题中声明。在头文件中真正声明的唯一函数是twodigits()
并且在这种情况下notwodigits()
被制成friend
s 以提供对index()
成员函数的访问。index()
成员函数只是分配一个在调用时间时可用的索引,std::ios_base::iword()
然后它只返回这个索引。操纵者 twodigits()
主要设置这个notwodigits()
索引。如果num_put
没有为流安装构面,twodigits()
也会安装构面:
std::ostream& twodigits(std::ostream& out)
{
if (!dynamic_cast<num_put const*>(
&std::use_facet<std::num_put<char> >(out.getloc()))) {
out.imbue(std::locale(out.getloc(), new num_put(out.getloc())));
}
out.iword(num_put::index()) = true;
return out;
}
std::ostream& notwodigits(std::ostream& out)
{
out.iword(num_put::index()) = false;
return out;
}
twodigits()
操纵器num_put
使用new num_put(out.getloc())
. 它不需要任何清理,因为在std::locale
对象中安装构面会进行必要的清理。使用 访问原始std::locale
流out.getloc()
。它被刻面改变。从理论上讲,notwodigits
可以恢复原始std::locale
而不是使用标志。但是,imbue()
这可能是一项相对昂贵的操作,使用标志应该便宜很多。当然,如果有很多类似的格式化标志,事情可能会变得不同......
为了演示操纵器的使用,下面有一个简单的测试程序。它设置了twodigits
两次格式化标志,以验证 facet 只创建一次(创建一个std::locale
s 链来通过格式化有点傻:
int main()
{
std::cout << "some-int='" << 1 << "' "
<< twodigits << '\n'
<< "two-digits1='" << 1 << "' "
<< "two-digits2='" << 2 << "' "
<< "two-digits3='" << 3 << "' "
<< notwodigits << '\n'
<< "some-int='" << 1 << "' "
<< twodigits << '\n'
<< "two-digits4='" << 4 << "' "
<< '\n';
}