首页 > 解决方案 > 将 char8_t const* 输出到 cout 和 wcout,一个编译一个不编译

问题描述

由于P1423R1为 char8_t、char16_t 和 char32_t 添加了已删除的 ostream 插入器,因此如果我们希望将这些类型流式传输到 ostream,我们暂时需要编写自定义运算符。尝试为 MSVC 2019 16.2.0 Preview 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但不会编译 for ,cout除非我取消注释非模板化operator<<for 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?无论哪种方式,这似乎都是错误。

标签: c++c++20

解决方案


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

表现出的行为符合 P1423R1 中指定的行为。在最近的 LWG 审查中,要求也删除宽流的 、 和相关char8_t重载char16_tchar32_tP1423R2 包含该更改,因此示例代码的编译也将在std::wcout何时/如果实现时失败。该修订版尚未在邮件中发布,但可以在https://rawgit.com/sg16-unicode/sg16/master/papers/p1423r2.html进行预览。

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


推荐阅读