将char8_t const* 输出到 cout 和 wcout,一个编译一个不编译

outputting char8_t const* to cout and wcout, one compiles one not

本文关键字:一个 编译 wcout char8 const cout 输出      更新时间:2023-10-16

由于P1423R1为char8_t、char16_t和char32_t添加了已删除的ostream插入器,因此如果我们希望将这些类型流式传输到ostreams,我们暂时处于需要编写自定义运算符的情况。尝试为 MSVC 2019 16.2.0 预览版 2.0 执行此操作时。

#include <iostream>
#include <string>
using namespace std::literals;
template<typename Tostream>
Tostream&
operator<<( Tostream& os, std::u8string_view string ) {
return os;
}
template<typename Tostream>
Tostream&
operator<<( Tostream& os, char8_t const* string ) {
return os << std::u8string_view( string );
}
/// this must be commented out to compile
//std::ostream&
//operator<<( std::ostream& os, char8_t const* string ) {
//  return os << std::u8string_view( string );
//}

int
main() {
std::cout << u8"utf-8"; 
std::wcout << u8"utf-8";
}

我发现我的模板化尝试成功了wcout但不会为cout编译,除非我取消注释非模板化operator<<char8_t const *

error C2280:  'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const char8_t *)': attempting to reference a deleted function

所以问题是,在哪种情况下是正确的?不为cout编译是对的还是为wcout编译是错误的?无论哪种方式,这似乎都是错误。

P1423 尚未被接受C++20(尽管它确实通过了 Kona 的 LEWG 审查),所以有趣的是Microsoft已经实现了(部分)它。

展示的行为与P1423R1中指定的行为相匹配。 在最近的LWG审查中,要求删除char8_tchar16_tchar32_t相关的重载。 P1423R2包括该更改,因此在实现示例代码时/如果实现该更改,示例代码的编译也将std::wcout失败。 该修订版尚未在邮件中发布,但可以在 https://rawgit.com/sg16-unicode/sg16/master/papers/p1423r2.html 预览。

正如@Nicol提到的,我们还没有就已删除重载的行为应该是什么达成共识。 他们应该隐式转码吗? 如果是这样,如何处理转码错误? 还是他们应该只流式传输字节? 但是,如果附加了codecvt分面(它将期望执行编码),会发生什么情况。 应该有std::u8out吗? 还是我们应该提供更好的转码工具并要求显式调用它们? 第16研究组将在C++23日努力回答这些问题。

非模板函数在重载解析方面始终优先于模板函数。因此,std::operator<<(std::ostream&, const char8_t*)将赢得您的模板版本。

此外,这些功能被删除的原因是不清楚它们应该有什么行为(或者更具体地说,委员会还没有准备好让Unicode成为现实的东西)。如果您的目标是将 UTF-8 编码字符串的字节写入字节流,那么您应该专门在一端执行此操作,方法是将u8字符串显式转换为字节 (char) 指针,然后打印:

std::cout << reinterpret_cast<const char*>(u8"utf-8");

不要试图强迫标准库做一些它明确不想做的事情。 特别是在这种情况下,当 C++23 可能会出现并提供这些功能的实现时。

相关文章: