2007/08/01

在 GCC 中同时使用 std::cout 和 std::wcout 的方法

在 GCC 3.4 以后,下面的程序会有问题:
#include 

int main()
{
  std::locale::global(std::locale("zh_CN.utf8"));
  std::cout << "Hello" << std::endl; // *
  std::wcout << L"你好" << std::endl;
  std::cout << "Hello" << std::endl;
}
程序的输出结果是:
Hello
`}
Hello
如果注释掉 * 行,则输出结果是:
你好
我们发现,如果首先使用了 std::cout ,那么 std::wcout 就会失效;如果首先使用 std::wcout ,那么 std::cout 就会失效。究其原因,C99 7.19.2 规定
5 Byte input/output functions shall not be applied to a wide-oriented stream and wide character input/output functions shall not be applied to a byte-oriented stream. The remaining stream operations do not affect, and are not affected by, a stream's orientation, except for the following additional restrictions: -- Binary wide-oriented streams have the file-positioning restrictions ascribed to both text and binary streams. -- For wide-oriented streams, after a successful call to a file-positioning function that leaves the file position indicator prior to the end-of-file, a wide character output function can overwrite a partial multibyte character; any file contents beyond the byte(s) written are henceforth indeterminate.
C++03 27.3 的规定是
2 Mixing operations on corresponding wide- and narrow-character streams follows the same semantics as mixing such operations on FILEs, as specified in Amendment 1 of the ISO C standard. The objects are constructed, and the associations are established at some time prior to or during first time an object of class ios_base::Init is constructed, and in any case before the body of main begins execution. The objects are not destroyed during program execution.
不清楚依据的是 C89 还是 C99 。不过有一点很清楚,即使现在的 C++ 标准允许 mixing ,以后也可能会禁止。请参考 libstdc++/27569 不过还是有办法的,在程序开始加入一句话:
#include 

int main()
{
  std::locale::global(std::locale("zh_CN.utf8"));
  std::ios::sync_with_stdio(false);
  std::cout << "Hello" << std::endl;
  std::wcout << L"你好" << std::endl;
  std::cout << "Hello" << std::endl;
}
不过这反而是个 bug 。参考 libstdc++/11705 还有一种方法,就是用 codecvt 自己写一个 to_wstring。像这样:
using namespace std;

string to_string(const wstring& wstr, const locale& loc = locale())
{
  typedef codecvt converter;
  const converter& cvt(use_facet(loc));
  mbstate_t stat;
  memset(&stat, 0, sizeof(stat));
  vector buf(cvt.max_length() * wstr.size());
  const wchar_t* wfrom = wstr.c_str();
  const wchar_t* wend = wfrom + wstr.size();
  const wchar_t* wnext = wfrom;
  char* from = &buf[0];
  char* end = from + buf.size();
  char* next = from;
  cvt.out(stat, wfrom, wend, wnext, from, end, next);
  return string(from, next);
}

wstring to_wstring(const string& str, const locale& loc = locale())
{
  typedef codecvt converter;
  const converter& cvt(use_facet(loc));
  mbstate_t stat;
  memset(&stat, 0, sizeof(stat));
  vector buf(str.size());
  const char* from = str.c_str();
  const char* end = from + str.size();
  const char* next = from;
  wchar_t* wfrom = &buf[0];
  wchar_t* wend = wfrom + buf.size();
  wchar_t* wnext = wfrom;
  cvt.in(stat, from, end, next, wfrom, wend, wnext);
  return wstring(wfrom, wnext);
}
其实有的时候还是很需要混合使用 std::coutstd::wcout 的,比如在国际化的程序里我会使用 wstring ,但是如果我想输出 locale 的名字就没办法了,因为 std::locale::name() 返回的是 string ,我只能用 std::cout 输出,这样就只能上面的两种方法了。

2005/12/20

boost::rational

boost::rational 是一个类似 std::complex 的 class template 。它提供了对分数的支持。它需要一个 template type parameter ,称作 underlying integer type 。 C++ 的任意 built-in integer types 都可以在这里使用;用户自定义的 integer type 也可以使用,但是必须是下面 concepts 的 model :
  • Assignable
  • Default Constructible
  • Equality Comparable
  • LessThan Comparable

而且, I 必须是一个 integer-like 型别。就是说,对于型别 I 的任意两个值 n and m ,下面的表达式必须合法,并且拥有“符合期望”的语义。

  • n + m
  • n - m
  • n * m
  • n / m (must truncate, and n/m must be positive if n and m are positive)
  • n % m (n%m must be positive if n and m are positive)
  • Assignment versions of the above
  • +n, -n

此型别中必须存在值 01 。并且能通过 I(0)I(1) 生成。(不过并不需要从整数到 I 的隐式转换,这里只需要用到 explicit constructor 。)

可以令 I 是一个 unsigned type ,这样派生出来的 rational class 也是 unsigned 。减法的结果将总是一个非负数,这时发生的 underflow behaviour 将是不确定的。

  • rational_cast(rational) 依赖于从 I 到 T 的 static_cast ,并且对型别 T 的任意两个值 x and y ,表达式 x/y 都合法。
  • 输入输出 operators 依赖于型别 I 对应的输入输出 operators 。

Utility Functions

下面两个函数用来计算给定两个数的最大公约数和最小公倍数,可以工作的型别必须已经定义这些 operations: =, +=, *=, /=, %, <>

gcd(n, m) The greatest common divisor of n and m
lcm(n, m) The least common multiple of n and m

在 boost::math 中也有同样功能的两个函数。不过这两对分别在不同的 namespace 中。

Constructors

Rationals 可以用一对 integers (numerator, denominator) 或者一个 integer 构造。还有一个 default constructor ,将 rational 初始化为 0 。

    I n, d;
   rational zero;
   rational r1(n);
   rational r2(n, d);

单参数的 constructor 没有被声明成 explicit ,因此可以进行从 underlying integer type 到 rational type 的隐式转换。

算术运算

rational class 支持所有的标准算术运算。

    +    +=
   -    -=
   *    *=
   /    /=
   ++   --    (both prefix and postfix)
   ==   !=
   <    >
   <=   >=

Input and Output

rational 的 external representation 是用一个 slash (/) 分开的两个 integer 。输入 rational 时,格式必须是一个 integer 后边紧跟一个 slash (不能有 whitespace ),再紧跟另一个 integer 。一个 integer 的 external representation 由 underlying integer type 。

In-place assignment

对任意的 rational rr.assign(n, m) 提供了一个相对于 r = rational(n, m); 更快速的等价表示,它不会生成中间变量。虽然这对于基于 machine integer types 的 rationals 是没有必要的,但是对于基于 unlimited-precision integers 的 rationals ,它可以减少开销。

Conversions

不存在从 rationals 到其它任何型别的隐式转换。然而,存在一个显式转换函数, rational_cast(r) 。可以这样使用:

    rational r(22,7);
   double nearly_pi = boost::rational_cast(r);

如果要转换的 rational 的 numerator 和 denominator 不能安全的 cast 到某种 floating point type ,或者 numerator 与 denominator 的除法不能正确计算(在要转换到的目标 floating point type 中)。

Numerator and Denominator

可以通过两个 member functions numerator() and denominator() 来访问 rational 的 internal representation

Exceptions

rational 的 denominator 不能是 0 (这个 lib 并不支持 infinity or NaN 这样的 represention )。一旦出现一个 denominator 是 0 的 rational ,将抛出 boost::bad_rational 异常。这只应该出现在当用户尝试显式构造一个 denominator 为 0 的 rational ,或者用 0 去除一个 rational 的情况下。

Internal representation

注意:这里讲述的是实现细节,不要依赖这里的信息编程。

在内部, rational 被保存为 a pair (numerator, denominator) of integers (它们的型别就是 rational 的 template type parameter )。 rationals 总是保存为最简分数的形式( gcd(numerator, denominator) = 1 ,并且 denominator 总是正数)。

2005/12/01

boost::any

boost::any 是一个可以存放多种型别数据的容器,并且保留了原数据的型别。
any 可存放的型别 ValueType 最少要满足如下条件:
  • CopyConstructible
  • optionally Assignable. 所有形式的 assignment 都要求有强异常安全保证。
  • destructor 不能抛出异常。

头文件 <boost/any.hpp>

namespace boost {
  class bad_any_cast;
  class any;
  template<typename ValueType> ValueType any_cast(const any &);
  template<typename ValueType> const ValueType * any_cast(const any *);
  template<typename ValueType> ValueType * any_cast(any *);
}
对一个 any 进行 any_cast 失败将抛出 boost::bad_any_cast 异常。

Synopsis

class
bad_any_cast : public std::bad_cast { public: virtual const char *
what() const; };
 
boost::any 是这个库的主要组件。

Synopsis

class any {
public:
  // construct/copy/destruct
  any();
  any(const any &);
  template<typename ValueType> any(const ValueType &);
  any & operator=(const any &);
  template<typename ValueType> any & operator=(const ValueType &);
  ~any();

  // modifiers
  any & swap(any &);

  // queries
  bool empty() const;
  const std::type_info & type() const;
};

Description

any construct/copy/destruct

  1. any();

    Postconditions: this->empty()

  2. any(const any & other);

    Effects: Copy constructor 将 other 中的内容复制到新的 instance 中,新的 instance 中的内容与 other 中是相等的,不论是型别还是值。如果 other 是 empty ,那么新的 instance 也是 empty 。

  3. Throws: 可能会抛出 std::bad_alloc 异常或者是任何来自被包含型别的 copy constructor 中的异常。

  4. template<typename ValueType> any(const ValueType & value);

    Effects: 制造一个 value 的副本,新的 instance 中的内容与 value 相等,不论是型别还是值。 Throws: std::bad_alloc 或者任何来自被包含型别的 copy constructor 中的异常。

  5. any & operator=(const any & rhs);

    Effects: 复制 rhs 中的内容到当前 instance ,放弃以前的内容, instance 中的新内容与 rhs 中是相等的,不论是型别还是值。如果 rhs 是 empty ,那么 instance 也是 empty 。 Throws: std::bad_alloc 或者任何来自被包含型别的 copy constructor 中的异常。 Assignment 满足强异常安全保证。

  6. template<typename ValueType> any & operator=(const ValueType & rhs);

    Effects: 制造一个 rhs 的副本,放弃以前的内容, 新内容与 rhs 相等,不论是型别还是值。 Throws: std::bad_alloc 或者任何来自被包含型别的 copy constructor 中的异常。 Assignment 满足强异常安全保证。

  7. ~any();

    Effects: 释放 instance 管理的所有被使用的资源。 Throws: Nothing.

any modifiers

  1. any & swap(any & rhs);

    Effects: 交换 *this 和 rhs 的内容。 Returns: *this Throws: Nothing.

any queries

  1. bool empty() const;

    Returns: true if instance is empty, otherwise false. Throws: Will not throw.

  2. const std::type_info & type() const;

    Returns: 如果 instance 非空,返回被包含值的 typeid 。否则返回 typeid(void). Notes: Useful for querying against types known either at compile time or only at runtime.

要取得 any 中的值,就必须使用 boost::any_cast 函数。

Synopsis

template<typename ValueType> ValueType any_cast(const any & operand);
template<typename ValueType> const ValueType * any_cast(const any * operand);
template<typename ValueType> ValueType * any_cast(any * operand);

Description

Returns: 如果传入一个 pointer , 操作成功则返回一个指向 operand 的内容 value 的指针,它有着与 value 相同的受限条件;否则返回 null 。如果传入一个值或引用,操作成功则返回内容 value 的一个副本。 Throws: 指针的重载版本不抛出异常;接受值或引用的重载版本如果操作失败就抛出 bad_any_castRationale: 值/引用版本返回一个副本,这是因为 C++ 内部转换运算返回的是副本。

值得注意的是 boost::any 是保留所包含的值的型别的, any_cast 在实现的时候先判断要转换的目标型别与原本所持有的型别的 typeid ,两者必须相等。因此 any 不能用来将数据在各种型别间转换。

2005/11/06

Boost Concept SignedInteger

Concept SignedInteger

SignedInteger

Notation(符号)

T
A type playing the role of integral-type in the SignedInteger concept.
x, y, z,
Objects of type T
a, b,
Objects of type int

Type expressions

Conversion to int

T must be convertible to int.

Valid expressions(有效表达式)

Name Expression Type

Conversion from int

T(a)

T

Preincrement

++x

T &

Predecrement

--x

T &

Postincrement

x++

T

Postdecrement

x--

T

Sum

x + y

T

Sum with int

x + a

T

Sum-assignment

x += y

T &

Sum-assignment with int

x += a

T &

Difference

x - y

T

Difference with int

x - a

T

Product

x * y

T

Product with int

x * a

T

Product-assignment with int

x *= a

T &

Product with int on left

a * x

T

Quotient

x / y

T

Quotient with int

x / a

T

Right-shift

x >> y

T

Right-shift with int

x >> a

T

Right-shift-assignment with int

x >>= a

T &

Less-than comparison

x <>

Convertible to bool

Less-than comparison with int

x <>

Convertible to bool

Less-than comparison with size_t

x <>()

Convertible to bool

Greater-than comparison

x > y

Convertible to bool

Greater-than comparison with int

x > a

Convertible to bool

Less-than-or-equal comparison

x <= y

Convertible to bool

Less-than-or-equal comparison with int

x <= a

Convertible to bool

Greater-than-or-equal comparison

x >= y

Convertible to bool

Greater-than-or-equal comparison with int

x >= a

Convertible to bool

Greater-than-or-equal comparison with int on left

a >= x

Convertible to bool

Equality comparison

x == y

Convertible to bool

Equality comparison with int

x == a

Convertible to bool

See also

2005/11/05

Boost Concept LessThanComparable

Concept LessThanComparable

LessThanComparable

Description(描述)

LessThanComparable 型别必须有 <, >, <=, and >= operators 。

Notation(符号)

X
A type playing the role of comparable-type in the LessThanComparable concept.
x, y,
Objects of type X

Valid expressions(有效表达式)

Name Expression Type Semantics

Less than

x <>

Convertible to bool

Determine if one value is less than another.

Less than or equal

x <= y

Convertible to bool

Determine if one value is less than or equal to another.

Greater than

x > y

Convertible to bool

Determine if one value is greater than another.

Greater than or equal to

x >= y

Convertible to bool

Determine if one value is greater than or equal to another.

Models

  • int

2005/11/04

Boost Concept EqualityComparable

Concept EqualityComparable

EqualityComparable

Description(描述)

Equality Comparable 型别必须有 == 和 != operators 。

Notation(符号)

X
A type playing the role of comparable-type in the EqualityComparable concept.
x, y,
Objects of type X

Valid expressions(有效表达式)

Name Expression Type

Equality test

x == y

Convertible to bool

Inequality test

x != y

Convertible to bool

Models

  • int
  • std::vector

2005/11/03

Boost Concept CopyConstructible

Concept CopyConstructible

CopyConstructible

Description(描述)

copy constructible 型别必须能够由此型别的另一个成员构造生成。

Notation(符号)

X
A type playing the role of copy-constructible-type in the CopyConstructible concept.
x, y
Objects of type X

Valid expressions(有效表达式)

Name Expression Type Semantics

Copy construction

X(x)

X

Require copy constructor.

Models

  • int