簡體   English   中英

帶有 u8、char8_t 和 std::string 的 C++20

[英]C++20 with u8, char8_t and std::string

C++11 為我們帶來了 UTF-8 字面量的 u8 前綴,幾年前我認為這很酷,並在我的代碼中加入了以下內容:

std::string myString = u8"●";

這一切都很好,但問題出現在 C++20 中,它似乎不再編譯了,因為 u8 創建了一個 char8_t* 並且這與僅使用 char 的 std::string 不兼容。

我應該創建一個新的 utf8string 嗎? 在 C++20 世界中,我們有更多與標准 std::string 並不真正匹配的顯式類型,做這種事情的一致和正確的方法是什么?

除了@lubgr 的回答之外,論文char8_t 向后兼容性修復 (P1423)討論了如何使用char8_t字符數組制作std::string幾種方法。

基本上的想法是,您可以將u8字符數組轉換為“普通”字符數組,以獲得與 C++17 及之前相同的行為,您只需要更明確一點。 本文討論了實現此目的的各種方法。

適合您的用例的最簡單(但不是完全零開銷,除非您添加更多重載)方法可能是最后一個,即引入顯式轉換函數:

std::string from_u8string(const std::string &s) {
  return s;
}
std::string from_u8string(std::string &&s) {
  return std::move(s);
}
#if defined(__cpp_lib_char8_t)
std::string from_u8string(const std::u8string &s) {
  return std::string(s.begin(), s.end());
}
#endif

我應該創建一個新的 utf8string 嗎?

不,它已經在那里了。 P0482不僅提出了char8_t ,而且還提出了std::basic_string的新特化,用於名為std::u8string char8_t字符類型。 所以這已經從主干用clanglibc++編譯了:

const std::u8string str = u8"●";

不幸的是,來自u8字面量的std::string構造中斷了。 從提案:

除了保留不贊成使用的接口外,該提案沒有指定任何向后兼容功能。 作者認為這些功能是必要的,但一組這樣的功能會不必要地損害本提案的目標。 相反,期望實現將提供選項以啟用更細粒度的兼容性功能。

但我想大多數這樣的初始化應該是grep able 或者受一些自動clang工具修復的影響。

我應該創建一個新的 utf8string 嗎?

不,C++20 添加了std::u8string 但是,我建議改用std::string因為標准中對char8_t的支持很差,並且根本不受任何系統 API 支持(並且可能永遠不會因為兼容性原因而支持)。 在大多數平台上,普通char字符串已經是 UTF-8,在 Windows 上,您可以使用 MSVC 編譯/utf-8 ,這將在主要操作系統上為您提供可移植的 Unicode 支持。

例如,您甚至無法在 C++20 中使用 u8 字符串編寫 Hello World 程序( https://godbolt.org/z/E6rvj5 ):

std::cout << u8"Hello, world!\n"; // won't compile in C++20

在使用 MSVC 和 C++20 之前的 Windows 上,情況更糟,因為 u8 字符串可能會被悄悄損壞。 例如:

std::cout << "Привет, мир!\n";

將產生有效的 UTF-8 可能會或可能不會顯示在控制台中,具體取決於其當前代碼頁,而

std::cout << u8"Привет, мир!\n";

幾乎肯定會給你一個無效的結果,例如╨а╤Я╨б╨В╨а╤С╨а╨Ж╨а┬╡╨бтАЪ, ╨а╤Ш╨а╤С╨б╨В! .

可能不方便,但是你用這個: (const char*)u8"こんにちは"

或者使用參數“const char*”和“const char8_t*”創建2個函數

目前看起來 utf8 到處都是擁護者,在決定如何處理可移植代碼的字符編碼時,C++20 提供了另一個有缺陷的不完整選項。 char8_t 進一步攪亂了一些已經很臟的水。 作為 msvc optionPreview - 來自最新 C++ 工作草案 (/std:c++latest) 的功能的止損,我能想到的最好的就是這個......

#if defined(__cpp_char8_t)
template<typename T>
const char* u8Cpp20(T&& t) noexcept 
{ 
#pragma warning (disable: 26490)
   return reinterpret_cast<const char*>(t);
#pragma warning (default: 26490)
}
   #define U8(x) u8Cpp20(u8##x)
#else
   #define U8(x) u8##x
#endif

它丑陋、低效且煩人。 但它允許在遺留的“utf8 無處不在”代碼中用 U8"" 替換所有 u8""。 我計划避開 char8_t,直到產品更加連貫和完整(或永遠)。 我們應該拭目以待,看看 C++20 最終會選擇什么。 目前 char8_t 是一個巨大的失望。

如果有人感興趣,我已經在 github 上發布了我自己的 utf8 隨處響應的開源示例(用於 Visual Studio 社區)。 https://github.com/JackHeeley/App3Dev

將 u8 文字用作const char*另一種方法是用戶定義的文字(請參閱https://en.cppreference.com/w/cpp/language/user_literal ):

std::string operator"" S(const char8_t* str, std::size_t) {
    return reinterpret_cast< const char* >(str);
}
char const* operator"" C(const char8_t* str, std::size_t) {
    return reinterpret_cast< const char* >(str);
}

用法:然后可以這樣使用:

std::string myString = u8"●"S;


SetConsoleOutputCP(CP_UTF8);
std::cout << u8"Привет, мир!"C << std::endl;

解釋

上面的代碼定義了兩個用戶定義的字面量u8"…"Su8"…"C (記住:C++20 中的字面量u8"…"const char8_t*類型)。 S文字創建了一個std::stringC文字創建了一個const char *

這意味着u8"…"C形式的所有文字都可以像"…"文字一樣使用,而u8"…"S形式的所有文字都可以像"…"s文字一樣使用。

PS:我不確定是否允許定義不以下划線“_”開頭的文字。 但是當我在 Visual Studio 中嘗試時,代碼運行沒有問題。 但是cppreference中的所有示例都帶有下划線。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM