第11.12.2章: 完整的 <iomanip> 参考

English

<iomanip> 头文件提供带参数的操纵器。这些操纵器会修改流的内部状态,而该状态会一直保留到你显式修改为止。这是根本性的设计缺陷 — 见第11.12章中“为什么 C++ iostream 有根本性缺陷”。fast_io 的操纵器是无状态的,不会遇到这些问题。

字段宽度与填充

操纵器 说明 示例
std::setw(n) 把最小字段宽度设为 n 个字符 std::cout << std::setw(10) << 42;
把填充字符设为 c Set fill character to c std::cout << std::setfill('0') << std::setw(5) << 42;

警告:std::setw 只作用于下一次输出操作,之后重置为 0。这不一致,而且容易出错。


#include <iostream>
#include <iomanip>

int main() {
    std::cout << std::setw(10) << 42 << '\n';  //         42
    std::cout << 42 << '\n';  // 42 (width reset!)

    std::cout << std::setfill('0') << std::setw(5) << 42 << '\n';  // 00042
    return 0;
}

数制

操纵器 说明 示例
std::setbase(n) 把数制设为 n(8、10 或 16) std::cout << std::setbase(16) << 255; (prints ff)

#include <iostream>
#include <iomanip>

int main() {
    std::cout << std::setbase(16) << 255 << '\n';  // ff
    std::cout << std::setbase(8) << 255 << '\n';   // 377
    std::cout << std::setbase(10) << 255 << '\n';  // 255
    return 0;
}

精度

操纵器 说明 示例
std::setprecision(n) 把浮点精度设为 n 位 std::cout << std::setprecision(3) << 3.14159; (prints 3.14)

注意:精度会一直保留到被修改为止。与 std::fixed 或 std::scientific 配合时,它控制小数位数。


#include <iostream>
#include <iomanip>

int main() {
    double pi = 3.14159;
    std::cout << std::setprecision(3) << pi << '\n';  // 3.14
    std::cout << pi << '\n';  // 3.14 (precision persists!)

    std::cout << std::fixed << std::setprecision(2) << pi << '\n';  // 3.14
    std::cout << std::scientific << std::setprecision(4) << pi << '\n';  // 3.1416e+00
    return 0;
}

其他操纵器

操纵器 说明
std::resetiosflags(f) 清除指定的格式标志
std::setiosflags(f) 设置指定的格式标志

格式标志包括:std::ios::left、std::ios::right、std::ios::internal、std::ios::dec、std::ios::hex、std::ios::oct、std::ios::fixed、std::ios::scientific、std::ios::boolalpha、std::ios::showbase、std::ios::showpoint、std::ios::showpos、std::ios::skipws、std::ios::uppercase、std::ios::unitbuf。


#include <iostream>
#include <iomanip>

int main() {
    // Set flags
    std::cout << std::setiosflags(std::ios::hex | std::ios::showbase);
    std::cout << 255 << '\n';  // 0xff

    // Reset flags
    std::cout << std::resetiosflags(std::ios::hex);
    std::cout << std::setiosflags(std::ios::dec);
    std::cout << 255 << '\n';  // 255

    return 0;
}

为什么这很糟糕

所有这些操纵器都会修改流的内部状态。看看这个:


#include <iostream>
#include <iomanip>

void print_hex(int value) {
    std::cout << std::hex << value << '\n';
    // Stream is now in hex mode!
}

int main() {
    print_hex(255);  // Prints "ff"
    std::cout << 255 << '\n';  // Also prints "ff"!
    // Must manually restore: std::cout << std::dec;
}

这是维护噩梦。你必须在每次使用后记得恢复流状态,否则后续代码会表现异常。异常可能把流留在不一致的状态。多个线程可能互相破坏对方的格式化。

fast_io 的操纵器无状态:


#include <fast_io.h>

void print_hex(int value) {
    using namespace ::fast_io::iomnp;
    println(::fast_io::mnp::hex(value));
    // No state to restore!
}

int main() {
    using namespace ::fast_io::iomnp;
    print_hex(255);  // Prints "ff"
    println(255);    // Prints "255" (decimal, as expected)
}

每个操纵器只作用于它包住的那个值。没有会被破坏的全局状态。