Не могу вставить число в пользовательский C ++ ostream / streambuf на основе char16_t

0

Я написал пользовательский std::basic_streambuf и std::basic_ostream потому что я хочу, чтобы поток вывода мог получить строку JNI таким же образом, как вы можете вызвать std::ostringstream::str(). Эти классы довольно просты.

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

Кроме того, я сделал четыре перегрузки operator<<, все в том же пространстве имен:

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

Реализация jni_utf16_streambuf::overflow(int_type) тривиальна. Он просто удваивает ширину буфера, помещает запрошенный символ и правильно устанавливает базовые, позиционные и конечные указатели. Он проверен, и я уверен, что он работает.

jni_utf16_ostream отлично работает с вставкой символов юникода. Например, это прекрасно работает и приводит к потоку, содержащему "привет, мир":

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

Моя проблема заключается в том, как только я попытаюсь вставить целочисленное значение, бит потока бит устанавливается, например:

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 :(

Я не понимаю, почему это происходит! Есть ли какой-нибудь другой метод на std::basic_streambuf мне нужно реализовать????

  • 0
    Я не слишком уверен, почему это происходит, но я верю, что это потому, что вам нужно определить перегрузку для целочисленных типов. Это работает, когда вы делаете приведение: o << (char16_t)x; // works
  • 0
    Тем не менее, есть операторы вставки, которые соответствуют моим утверждениям. Не имеет смысла определять эти операторы, а просто устанавливать плохие биты!
Показать ещё 2 комментария
Теги:
c++11
mingw
iostream
g++4.8

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" backend не может быть создан в качестве незаменимых символов, а также не может быть создан также грань codecvt.

Visual Studio 2010 (MSVC10)/C++ 0x Статус

Однако MSVC предоставляет все необходимые грани:

Стандартная библиотека не предоставляет установки std :: locale :: id для этих граней в DLL, поэтому она не может использоваться с флагами компилятора /MD,/MDd и требует статической ссылки библиотеки времени выполнения. char16_t и char32_t не являются отдельными типами, а скорее псевдонимами беззнаковых коротких и неподписанных типов, что противоречит требованиям C++ 0x, что делает невозможным запись char16_t/char32_t в поток и вызывает множественные ошибки.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню