Boost C++ 库

...世界上最受推崇和专业设计的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu, C++ 编码标准

此库包含用于标准 I/O 库的各种实用程序。

IO 状态保存器, <boost/io/ios_state.hpp>

描述

头文件 <boost/io/ios_state.hpp> 涵盖了保存 C++ IOStreams 系统中对象流状态的功能。

原理

有时,某个值只需要在有限的范围内更改。 Saver 类保存某个对象(或对象的某个方面)当前状态的副本,并在销毁时重置对象的状态,从而撤消对象可能经历的任何更改。

当使用 I/O 流对象时,saver 类策略非常有用。操纵器对象可以在输入或输出期间更改流的某些方面。操纵器更改的状态通常在 I/O 事务后保持其新值。如果在不应外部更改流状态的函数中使用操纵器,这可能会成为问题。

#include <ostream>
#include <ios>

void hex_my_byte(std::ostream& os, char byte)
{
    os << std::hex << static_cast<unsigned>(byte);
}

在调用 hex_my_byte 后,os 流将保留其新的十六进制打印模式。可以使用手动调用流的状态检查和修改成员函数来保存和恢复流的打印模式。如果主要功能复杂和/或需要异常安全,则手动方法变得笨拙。 saver 类可以实现更好的“资源获取即初始化”策略。

请参阅下面的示例,了解使用 saver 类的更佳代码。

头文件概要

namespace boost {
namespace io {

class ios_flags_saver;
class ios_precision_saver;
class ios_width_saver;
class ios_base_all_saver;

template<class Ch, class Tr = std::char_traits<Ch> >
class basic_ios_iostate_saver;

template<class Ch, class Tr = std::char_traits<Ch> >
class basic_ios_exception_saver;

template<class Ch, class Tr = std::char_traits<Ch> >
class basic_ios_tie_saver;

template<class Ch, class Tr = std::char_traits<Ch> >
class basic_ios_rdbuf_saver;

template<class Ch, class Tr = std::char_traits<Ch> >
class basic_ios_fill_saver;

template<class Ch, class Tr = std::char_traits<Ch> >
class basic_ios_locale_saver;

template<class Ch, class Tr = std::char_traits<Ch> >
class basic_ios_all_saver;

typedef basic_ios_iostate_saver<char>      ios_iostate_saver;
typedef basic_ios_iostate_saver<wchar_t>   wios_iostate_saver;
typedef basic_ios_exception_saver<char>    ios_exception_saver;
typedef basic_ios_exception_saver<wchar_t> wios_exception_saver;
typedef basic_ios_tie_saver<char>          ios_tie_saver;
typedef basic_ios_tie_saver<wchar_t>       wios_tie_saver;
typedef basic_ios_rdbuf_saver<char>        ios_rdbuf_saver;
typedef basic_ios_rdbuf_saver<wchar_t>     wios_rdbuf_saver;
typedef basic_ios_fill_saver<char>         ios_fill_saver;
typedef basic_ios_fill_saver<wchar_t>      wios_fill_saver;
typedef basic_ios_locale_saver<char>       ios_locale_saver;
typedef basic_ios_locale_saver<wchar_t>    wios_locale_saver;
typedef basic_ios_all_saver<char>          ios_all_saver;
typedef basic_ios_all_saver<wchar_t>       wios_all_saver;

class ios_iword_saver;
class ios_pword_saver;
class ios_all_word_saver;

} // io
} // boost

基本标准属性的保存器

基本 saver 类具有以下格式

class saver {
public:
    typedef std::ios_base state_type;
    typedef implementation_defined aspect_type;

    explicit saver(state_type& s);
    saver(state_type& s, const aspect_type& new_value);
    ~saver();

    void restore();
};

state_type 是 IOStreams 基类 std::ios_base。用户通常会为 state-type 参数放置实际的输入、输出或组合流对象,而不是基类对象。第一个构造函数接受一个流对象,并保存对流的引用以及特定流属性的当前值。第二个构造函数的工作方式与第一个构造函数类似,并使用其第二个参数将流的属性更改为给定的新 aspect_type 值。析构函数将流的属性恢复为保存的值。可以使用 restore 成员函数提前(且经常)激活恢复。

表 1. 基本 IOStreams 状态 Saver 类
已保存的属性 属性类型 读取方法 写入方法

ios_flags_saver

格式控制标志

std::ios_base::fmtflags

flags

flags

ios_precision_saver

小数点后打印的位数

std::streamsize

precision

precision

ios_width_saver

打印对象的最小字段宽度

std::streamsize

width

width

高级标准属性的保存器

saver 类模板具有以下格式

template<class Ch, class Tr>
class saver {
public:
    typedef std::basic_ios<Ch, Tr> state_type;
    typedef implementation-defined aspect_type;

    explicit saver(state_type& s);
    saver(state_type& s, const aspect_type& new_value);
    ~saver();

    void restore();
};

state_type 是 IOStreams 基类模板 std::basic_ios<Ch, Tr> 的一个版本,其中 Ch 是字符类型,Tr 是字符 traits 类。用户通常会为 state-type 参数放置实际的输入、输出或组合流对象,而不是基类对象。第一个构造函数接受一个流对象,并保存对流的引用以及特定流属性的当前值。第二个构造函数的工作方式与第一个构造函数类似,并使用其第二个参数将流的属性更改为给定的新 aspect_type 值。析构函数将流的属性恢复为保存的值。可以使用 restore 成员函数提前(且经常)激活恢复。

表 2. 高级 IOStreams 状态 Saver 类模板
已保存的属性 属性类型 读取方法 写入方法

basic_ios_iostate_saver<Ch, Tr>

流的失败状态 [1], [2]

std::ios_base::iostate

rdstate

clear

basic_ios_exception_saver<Ch, Tr>

哪些失败状态触发异常 [1]

std::ios_base::iostate

exceptions

exceptions

basic_ios_tie_saver<Ch, Tr>

与流同步的输出流

std::basic_ostream<Ch, Tr>*

tie

tie

basic_ios_rdbuf_saver<Ch, Tr>

与流关联的流缓冲区 [2]

std::basic_streambuf<Ch, Tr>*

rdbuf

rdbuf

basic_ios_fill_saver<Ch, Tr>

用于填充超大字段宽度的字符

Ch

fill

fill

basic_ios_locale_saver<Ch, Tr>

与流关联的区域设置信息 [3]

std::locale

getloc (来自 std::ios_base)

imbue (来自 std::basic_ios<Ch, Tr>)

注释

  1. 当失败状态标志和/或失败状态异常监视标志更改时,如果在两组标志之间发生匹配,则会抛出异常。 这可能意味着这些类模板的构造函数或析构函数可能会抛出异常。

  2. 当关联的流缓冲区被更改时,如果给定的流缓冲区的地址为非 NULL,则流的失败状态集将重置为“good”,但如果该地址为 NULL,则会设置“bad”失败状态。 这意味着,如果流被剥夺了关联的流缓冲区,则保存的“good”失败状态可能会恢复为“bad”。 更糟糕的是,给定一个 NULL 流缓冲区地址,如果正在监视“bad”失败状态,则会抛出异常。 这可能意味着这些类模板的构造函数或析构函数可能会抛出异常。

  3. 区域设置的 saver 使用 std::basic_ios<Ch, Tr> 类来提取其信息,尽管它可以使用 std::ios_base 中的功能。 问题是 ios_base 中所需成员函数的版本与 basic_ios 中的版本不是多态相关的。 将与 saver 类一起使用的流类应使用与其继承最接近的成员函数版本,这意味着 basic_ios 中的版本。

用户自定义属性的保存器

有三个用于组合属性 saver 的类(模板)。 ios_base_all_saver saver 类结合了所有基本属性 saver 类的功能。 它有一个构造函数,该构造函数接受要保留其状态的流。 basic_ios_all_saver 结合了所有高级属性 saver 类模板和组合的基本属性 saver 类的功能。 它有一个构造函数,该构造函数接受要保留其状态的流。 ios_all_word_saver saver 类结合了保留用户定义的格式化信息的 saver 类。 它的构造函数接受要保存其属性的流以及用户定义的属性的索引。 每个类的析构函数都会恢复保存的状态。 对于具有 restore 成员函数的类,可以提前(且经常)激活恢复。

示例

原理中使用的代码可以在两个地方改进。 打印函数可以在更改格式化状态的代码周围使用 saver。 或者,调用函数可以用 saver 包围调用。 或者两者都可以完成,特别是如果用户不知道打印函数是否使用状态 saver。 如果用户想要一系列来回更改,而无需将每个更改都包含在单独的块中,则可以在每次尝试之间调用 restore 成员函数。

#include <boost/io/ios_state.hpp>
#include <ios>
#include <iostream>
#include <ostream>

void new_hex_my_byte(std::ostream& os, char byte)
{
    boost::io::ios_flags_saver ifs(os);
    os << std::hex << static_cast<unsigned>(byte);
}

int main()
{
    // ...
    {
        boost::io::ios_all_saver ias(std::cout);
        new_hex_my_byte(std::cout, 'A');
    }
    // ...
    {
        boost::io::ios_all_saver ias(std::cerr);
        new_hex_my_byte(std::cerr, 'b');
        ias.restore();
        new_hex_my_byte(std::cerr, 'C');
    }
    // ...
}

鸣谢

Daryle Walker

启动了库。 贡献了格式标志、精度、宽度和用户定义的格式标志 saver 类的初始版本。 贡献了成功状态、成功状态异常标志、输出流 tie、流缓冲区、字符填充和区域设置 saver 类模板的初始版本。 贡献了组合属性类和类模板。 贡献了测试文件 ios_state_test.cpp

历史

2019 年 12 月 20 日

Glen Fernandes 使所有 saver 类都不可复制。

2005 年 2 月 28 日

Daryle Walker 根据 Gennadiy Rozental 和 Rob Stewart 的建议添加了 restore 成员函数。

2002 年 3 月 13 日

Daryle Walker 实现了初始版本。

带引号的操纵器, <boost/io/quoted.hpp>

简介

C++ 标准库流 I/O 对于包含嵌入空格的字符串可能会产生意外的结果。 例如,

std::stringstream ss;
std::string original = "fooled you";
std::string roundtrip;

ss << original;
ss >> roundtrip;

std::cout << original;   // outputs: fooled you
std::cout << roundtrip; // outputs: fooled

assert(original == roundtrip); // assert will fire

Boost quoted 流 I/O 操纵器在输出时在字符串周围放置分隔符(默认为双引号 (")),并在输入时剥离分隔符。 这确保了带有嵌入空格的字符串按预期往返。 例如,

std::stringstream ss;
std::string original = "fooled you";
std::string roundtrip;

ss << quoted(original);
ss >> quoted(roundtrip);

std::cout << quoted(original); // outputs: "fooled you"
std::cout << roundtrip;       // outputs: fooled you

assert(original == roundtrip); // assert will not fire

如果字符串包含分隔符字符,则在输出时,该字符将在转义字符之前,转义字符本身也是如此

std::cout << quoted("'Jack & Jill'", '&', '\''); // outputs: '&'Jack && Jill&''

头文件概要

namespace boost {
namespace io {

template<class Char, class Traits, class Alloc>
unspecified-type1
quoted(const std::basic_string<Char, Traits, Alloc>& string,
       Char escape='\\', Char delim='\"');

template<class Char>
unspecified-type2
quoted(const Char* string, Char escape='\\', Char delim='\"');

template<class Char, class Traits, class Alloc>
unspecified-type3
quoted(std::basic_string<Char, Traits, Alloc>& string,
       Char escape='\\', Char delim='\"');

} // io
} // boost

unspecified-type1unspecified-type2unspecified-type3 是实现提供的类型,具有实现提供的 operator<<

template<class Char, class Traits>
std::basic_ostream<Char, Traits>&
operator<<(std::basic_ostream<Char, Traits>& os,
           const unspecified-typeN& proxy);
效果

将字符插入到 os

  • delim

  • string 中的每个字符。 如果要输出的字符等于 escapedelim(由 operator== 确定),则首先输出 escape

  • delim

备注

stringescapedelim 具有调用构造 proxyquoted 函数的相应参数的类型和值。

返回

os.

unspecified-type3 是实现提供的类型,具有实现提供的 operator>>

template<class Char, class Traits>
std::basic_istream<Char, Traits>&
operator>>(std::basic_istream<Char, Traits>& is,
           const unspecified-type3& proxy);
效果

os 中提取字符

  • 如果提取的第一个字符等于 delim(由 operator== 确定),则

    • 关闭 skipws 标志。

    • string.clear()

    • 在到达未转义的 delim 字符或 is.not_good() 之前,从 os 中提取字符并将它们附加到字符串,除非到达转义符,否则忽略它并将下一个字符附加到字符串。

    • 丢弃最终的 delim 字符。

    • skipws 标志恢复为其原始值。

  • 否则,os >> string

备注

stringescapedelim 具有调用构造 proxyquoted 函数的相应参数的类型和值。

返回

is.

致谢

quoted() 流操纵器源于 Boost 开发者邮件列表上的讨论。 参与者包括 Beman Dawes、Rob Stewart、Alexander Lamaison、Eric Niebler、Vicente Botet、Andrey Semashev、Phil Richards 和 Rob Murray。 Eric Niebler 的建议为模板的名称和形式奠定了基础。

Beman Dawes 开始将 quoted() 的实现作为私有详细信息头文件。 Glen Fernandes 更新了实现,并使其公开。

Glen Fernandes 更正了实现,以正确考虑流宽度和填充,并对其进行了优化,使其可以直接写入流缓冲区。

带分隔符的迭代器, <boost/io/ostream_joiner.hpp>

描述

头文件 <boost/io/ostream_joiner.hpp> 提供了类模板 boost::io::ostream_joiner,它是一个输出迭代器,用于将对象写入 std::basic_ostream,并用分隔符分隔。 它是 Library Fundamentals TS std::ostream_joiner 的实现,支持 C++03 及更高版本。

示例

以下程序将向量的内容写入标准输出,每个元素用逗号分隔。

#include <boost/io/ostream_joiner.hpp>
#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v;
    v.push_back(2);
    v.push_back(4);
    v.push_back(6);
    v.push_back(8);
    std::copy(v.begin(), v.end(), boost::make_ostream_joiner(std::cout, ','));
}

参考

头文件概要

namespace boost {
namespace io {

template<class Delim, class Char = char,
    class Traits = std::char_traits<Char> >
class ostream_joiner {
public:
    typedef Char char_type;
    typedef Traits traits_type;
    typedef std::basic_ostream<Char, Traits> ostream_type;
    typedef std::output_iterator_tag iterator_category;
    typedef void value_type;
    typedef void difference_type;
    typedef void pointer;
    typedef void reference;

    ostream_joiner(ostream_type& output, const Delim& delim);
    ostream_joiner(ostream_type& output, Delim&& delim);

    template<class T>
    ostream_joiner& operator=(const T& value);

    ostream_joiner& operator*() noexcept;
    ostream_joiner& operator++() noexcept;
    ostream_joiner& operator++(int) noexcept;
};

template<class Char, class Traits, class Delim>
ostream_joiner<std::decay_t<Delim>, Char, Traits>
make_ostream_joiner(std::basic_ostream<Char, Traits>& output, Delim&& delim);

} // io
} // boost

构造函数

ostream_joiner(ostream_type& output, const Delim& delim);
效果

使用 std::addressof(output) 初始化对流的存储引用,并使用 delim 初始化存储的分隔符。

ostream_joiner(ostream_type& output, Delim&& delim);
效果

使用 std::addressof(output) 初始化对流的存储引用,并使用 std::move(delim) 初始化存储的分隔符。

成员函数

template<class T>
ostream_joiner& operator=(const T& value);
效果

如果是首次调用此成员函数,则将存储的分隔符写入存储的流引用。 将 value 写入存储的流引用。

返回

*this.

ostream_joiner& operator*() noexcept;
ostream_joiner& operator++() noexcept;
ostream_joiner& operator++(int) noexcept;
返回

*this.

自由函数

template<class Char, class Traits, class Delim>
ostream_joiner<decay_t<Delim>, Char, Traits>
make_ostream_joiner(std::basic_ostream<Char, Traits>& output, Delim&& delim);
返回

ostream_joiner<std::decay_t<Delim>, Char, Traits>(output, std::forward<Delim>(delim)).

致谢

Glen Fernandes 实现了 ostream_joinermake_ostream_joiner

插入格式化输出, <boost/io/ostream_put.hpp>

描述

头文件 <boost/io/ostream_put.hpp> 提供了函数模板 boost::io::ostream_put,用于满足 [ostream.formatted.reqmts] 要求的格式化输出。

示例

类模板 basic_string_view 的插入器可以如下实现

template<class charT, class traits>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os,
    const basic_string_view<charT, traits>& str)
{
    return boost::io::ostream_put(os, str.data(), str.size());
}

参考

头文件概要

namespace boost {
namespace io {

template<class charT, class traits>
std::basic_ostream<charT, traits>&
ostream_put(std::basic_ostream<charT, traits>& os,
    const charT* data, std::size_t size);

} // io
} // boost

自由函数

template<class charT, class traits>
std::basic_ostream<charT, traits>&
ostream_put(std::basic_ostream<charT, traits>& os,
    const charT* data, std::size_t size);
效果

行为类似于 os 的格式化插入器(如 [ostream.formatted.reqmts] 中所述)。 创建一个字符序列 seq,其大小为 characters,从 data 开始,每个字符都使用 os.widen() ([basic.ios.members]) 加宽。 确定 seq 的填充,如 [ostream.formatted.reqmts] 中所述。 将 seq 插入到 os 中。 调用 width(0)

返回

os.

致谢

Glen Fernandes 更新了 basic_string_refbasic_string_view 流插入运算符的实现,以直接写入 basic_streambuf,并将该功能重构到此通用实用程序中。

空流, <boost/io/nullstream.hpp>

描述

头文件 <boost/io/nullstream.hpp> 提供了类模板 boost::io::basic_nullbuf,它是一个空流缓冲区,以及类模板 boost::io::basic_onullstream,它是一个空流。

示例

以下程序将空流传递给函数。

#include <boost/io/ostream_joiner.hpp>
#include <fstream>

void setup(std::ostream& log);

int main(int argc, char* argv[])
{
    if (argc == 2) {
        std::ofstream file(argv[1]);
        setup(file);
    } else {
        boost::io::onullstream none;
        setup(none);
    }
}

参考

头文件概要

namespace boost {
namespace io {

template<class CharT, class Traits = std::char_traits<Char> >
class basic_nullbuf
    : public std::basic_streambuf<CharT, Traits> {
protected:
    typename Traits::int_type overflow(typename Traits::int_type c) override;

    std::streamsize xsputn(const CharT*, std::streamsize n) override;
};

template<class CharT, class Traits = std::char_traits<CharT> >
class basic_onullstream
    : public std::basic_ostream<CharT, Traits> {
public:
    basic_onullstream();
};

typedef basic_onullstream<char> onullstream;
typedef basic_onullstream<wchar_t> wonullstream;

} // io
} // boost

致谢

Glen Fernandes 实现了 basic_nullbufbasic_onullstream

  • 版权所有 2002 Daryle Walker

  • 版权所有 2002, 2006, 2007, 2009, 2010 Beman Dawes

  • 版权所有 2019 Glen Joseph Fernandes