2016-12-12 14 views
6

Если вы кормите wchar_t, char16_t или char32_t значение узкой ostream, он будет печатать числовое значение точки кода.iostreams - Печать `` wchar_t` или значение charXX_t` как символ

#include <iostream> 
using std::cout; 
int main() 
{ 
    cout << 'x' << L'x' << u'x' << U'x' << '\n'; 
} 

принты x120120120. Это связано с тем, что существует operator<< для конкретной комбинации basic_ostream с ее номером charT, но для других типов символов нет аналогичных операторов, поэтому они автоматически преобразуются в int и печатаются таким образом. Точно так же, не узкие строковые литералы (L"x", u"x", U"X") будут бесшумно преобразованы в void* и печатаются в качестве значения указателя, и не узкие объектов снабжать струну, тетивой (wstring, u16string, u32string) не будет даже компиляция.

Итак, вопрос: Что является наименее ужасным способом печати wchar_t, char16_t или char32_t значения а на узкую ostream, как символ, а не в качестве числового значения элемента коды? Он должен правильно преобразовать все кодовых точек, которые представляются в кодировке ostream, для этой кодировки и должны сообщать об ошибке, когда код не представлен. (Так, например, при u'…' и UTF-8 ostream, последовательность из трех байтов 0xE2 0x80 0xA6 должны быть записаны в поток, но учитывая u'â' и KOI8-R ostream, следует сообщать об ошибке.)

Аналогично , как можно печатать не узкий C-string или строковый объект в узком ostream, преобразовывая в выходную кодировку?

Если это невозможно сделать в соответствии с ISO C++ 11, я возьму ответы на конкретные платформы.

(Вдохновленный this question.)

+2

Короче говоря, вы должны либо 1) использовать широкий ostream, или 2) преобразуете широкие символьные данные в узком кодирующих себя (что является потенциально потерями преобразования). Ostream не может сделать это преобразование для вас. Посмотрите на ['std :: wstring_convert'] (http: //en.cppreference.com/w/cpp/locale/wstring_convert) или использовать библиотеку, например [ICONV] (https://www.gnu.org/software/libiconv/) или [ICU] (http: //site.icu-project. орг /). –

ответ

2

Как вы отметили, что нет operator<<(std::ostream&, const wchar_t) для узкого ostream. Если вы хотите использовать синтаксис, вы можете научить ostream, как это сделать с wchar s, чтобы эта процедура была выбрана как лучшая перегрузка, которая первой требует преобразования в целое число.

Если вы чувствуете приключения:

namespace std { 
    ostream& operator<< (ostream& os, wchar_t wc) { 
    if(unsigned(wc) < 256) // or another upper bound 
     return os << (unsigned char)wc; 
    else 
     throw your_favourite_exception; // or handle the error in some other way 
    } 
} 

В противном случае, сделать простую struct что прозрачно охватывает wchar_t и имеет настраиваемый friend operator<< и конвертировать широкие символы, которые перед выводом их.

Edit: Для того, чтобы на лету преобразование и из местности, вы можете использовать функции из <cwchar>, как:

ostream& operator<< (ostream& os, wchar_t wc) { 
    std::mbstate_t state{}; 
    std::string mb(MB_CUR_MAX, '\0'); 
    size_t ret = std::wcrtomb(&mb[0], wc, &state); 
    if(ret == static_cast<std::size_t>(-1)) 
     deal_with_the_error(); 
    return os << mb; 
} 

Не забудьте установить локаль в система по умолчанию:

std::locale::global(std::locale("")); 
std::cout << L'ŭ'; 
+0

Это не преобразует значение в узкую выходную кодировку. Это важно, и это тоже часть, которую я еще не знаю, как это сделать. – zwol

+0

@zwol. Как еще вы хотели бы преобразовать широкий символ, чем принять его, если он находится в ASCII и отклоняется иначе? Тогда вам нужно быть конкретным, например, удалять акценты или что-то еще. –

+0

В вашем примере используется 'x', который передает это (для 'L'x'', вам нужно будет сделать то же самое для других типов), поэтому я предположил, что это то, что вам нужно. –