0

I have written a custom std::basic_streambuf and std::basic_ostream because I want an output stream that I can get a JNI string from in a manner similar to how you can call std::ostringstream::str(). These classes are quite simple.

namespace myns {

class jni_utf16_streambuf : public std::basic_streambuf<char16_t>
{
    JNIEnv * d_env;
    std::vector<char16_t> d_buf;
    virtual int_type overflow(int_type);

public:
    jni_utf16_streambuf(JNIEnv *);
    jstring jstr() const;
};

typedef std::basic_ostream<char16_t, std::char_traits<char16_t>> utf16_ostream;

class jni_utf16_ostream : public utf16_ostream
{
    jni_utf16_streambuf d_buf;

public:
    jni_utf16_ostream(JNIEnv *);
    jstring jstr() const;
};

// ...

} // namespace myns

In addition, I have made four overloads of operator<<, all in the same namespace:

namespace myns {

// ...

utf16_ostream& operator<<(utf16_ostream&, jstring) throw(std::bad_cast);

utf16_ostream& operator<<(utf16_ostream&, const char *);

utf16_ostream& operator<<(utf16_ostream&, const jni_utf16_string_region&);

jni_utf16_ostream& operator<<(jni_utf16_ostream&, jstring);

// ...

} // namespace myns

The implementation of jni_utf16_streambuf::overflow(int_type) is trivial. It just doubles the buffer width, puts the requested character, and sets the base, put, and end pointers correctly. It is tested and I am quite sure it works.

The jni_utf16_ostream works fine inserting unicode characters. For example, this works fine and results in the stream containing "hello, world":

myns::jni_utf16_ostream o(env);
o << u"hello, wor" << u'l' << u'd';

My problem is as soon as I try to insert an integer value, the stream's bad bit gets set, for example:

myns::jni_utf16_ostream o(env);
if (o.badbit()) throw "bad bit before"; // does not throw
int32_t x(5);
o << x;
if (o.badbit()) throw "bad bit after"; // throws :(

I don't understand why this is happening! Is there some other method on std::basic_streambuf I need to be implementing????

4

1 回答 1

1

看起来答案是char16_t在 GCC 4.8 中仅部分实现了支持。库头文件不安装转换数字所需的方面。以下是 Boost.Locale 项目所说的

GNU GCC 4.5/C++0x 状态

然而,GNU C++ 编译器提供了对 C++0x 字符的良好支持:

标准库没有为此支持安装任何 std::locale::facets,因此任何使用 char16_t 或 char32_t 流格式化数字的尝试都会失败。标准库缺少所需的 char16_t/char32_t 语言环境方面的专业化,因此“std”后端无法构建,因为缺少基本符号,也无法创建 codecvt 方面。

Visual Studio 2010 (MSVC10)/C++0x 状态

但是,MSVC 提供了所有必需的方面:

标准库不为 DLL 中的这些方面提供 std::locale::id 安装,因此它不能与 /MD、/MDd 编译器标志一起使用,并且需要运行时库的静态链接。char16_t 和 char32_t 不是不同的类型,而是 unsigned short 和 unsigned 类型的别名,这与 C++0x 要求相矛盾,因此无法将 char16_t/char32_t 写入流式传输并导致多个错误。

于 2013-11-06T04:44:24.843 回答