将char8_t const* 输出到 cout 和 wcout,一个编译一个不编译
outputting char8_t const* to cout and wcout, one compiles one not
由于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_t
、char16_t
和char32_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 可能会出现并提供这些功能的实现时。