Как я могу получить wstring_convert :: to_bytes, чтобы вызвать исключение range_error?

я использую std::wstring_convert преобразовать wstring в многобайтовую строку следующим образом:

    // convert from wide char to multibyte char
try
{
return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(wideMessage);
}

// thrown by std::wstring_convert.to_bytes() for bad conversions
catch (std::range_error& exception)
{
// do something...
}

Для модульного тестирования блока я прокомментировал как do something... Я хочу передать wstring, который бросит std::range_error исключение.

Однако я не смог сформулировать такую ​​строку, которая потерпит неудачу при таком преобразовании. Wstring будет использовать UTF16, и я читал о высоких и низких суррогатах. Например, символ UTF16 D800, за которым следует «b», должен быть недействительным. std::wstring(L"\xd800b"); не компилируется по тем же причинам, возможно. Если я создам wstring, как показано ниже, он не выдаст исключение при преобразовании:

std::wstring wideMessage(L" b");
wideMessage[0] = L'\xd800';

// doesn't throw
std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(wideMessage);

Есть ли подходящая строка, которую я могу использовать, чтобы вызвать исключение во время преобразования?

Я пробовал 5.1, 5.2 и 5.3 из эта ссылка. Я использую Visual Studio 2015.

4

Решение

Реализация Microsoft std::codecvt_utf8 похоже, успешно преобразует любую кодовую единицу UTF-16 в UTF-8, включая суррогатные пары. Это ошибка, поскольку суррогаты не кодируются. И libc ++ (LLVM), и libstdc ++ (GCC) будут правильно генерировать std::range_error и не в состоянии преобразовать непарных суррогатов.

Глядя на их код, кажется, что единственный способ бросить это, если символ больше, чем Maxcode параметр шаблона фасета. Например:

std::wstring_convert<std::codecvt_utf8<wchar_t, 0x1>>
4

Другие решения

Как указано 一 二三 (принятый ответ) Реализация Microsoft codecvt_utf8 кажется, прослушивается.

Я знаю, что строки, с которыми я имею дело, всегда UTF16, и я хочу преобразовать в UTF8. Я закончил тем, что изменил реализацию следующим образом:

    // convert from wide char to multibyte char
try
{
return std::wstring_convert<std::codecvt_utf8_utf16 <wchar_t>>().to_bytes(wideMessage);
}

// thrown by std::wstring_convert.to_bytes() for bad conversions
catch (const std::range_error & exception)
{
// do something...
}

Следующее теперь будет бросать правильно:

std::wstring wideMessage(L" b");
wideMessage[0] = L'\xd800';

// throw std::range_error
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().to_bytes(wideMessage);

Я бы никогда не нашел эту ошибку без юнит-тестирования!

1

По вопросам рекламы ammmcru@yandex.ru