Authors: Jan Schultke, Peter Bindels
Document: P3876R1
Date: 2026-02-22
Target: SG16
Link: wg21.link/p3876r1
Jan Schultke and Peter Bindels propose extending std::to_chars and std::from_chars to work with char8_t, char16_t, char32_t, and wchar_t - not just char. The motivation is straightforward: if you're building a JSON parser with char8_t strings, you currently can't convert numbers without going through char first. Since every digit and sign that charconv touches is Basic Latin (ASCII), supporting other character types is mechanically simple.
The main design challenge is avoiding overload explosion. Adding non-template overloads for every character type times every arithmetic type would give you around 110 functions, so the paper uses function templates constrained by a character-type concept instead. The existing result types (to_chars_result, from_chars_result) can't be templated without breaking ABI, so new per-character-type result structs are introduced along with alias templates.
SG16 reviewed R0 in early 2026 with consensus in favor, though char16_t support only got weak consensus. R1 incorporates that feedback with minor fixes and rebased wording.
The year is 2026 and we're standardizing
wchar_toverloads forcharconv. I love this timeline.Some of us deal with Win32 APIs every single day. Being able to
to_charsdirectly into awchar_tbuffer instead of converting throughcharand thenMultiByteToWideCharis genuinely useful. Not everything is Linux.Finally. I've been doing
reinterpret_cast<const char*>on myu8string_viewbuffers before feeding them tofrom_charsfor two years now. It works but it feels deeply wrong.Now do
std::formatwithchar8_tformat strings. Andstd::print(u8""). Please. I'm begging.SG16 already polled on this during Q1 2026. Consensus was clear for
to_chars,from_chars,char8_t,char32_t, andwchar_t. Butchar16_tonly got weak consensus - 4 strongly in favor, 0 in favor, 4 neutral, 1 against.I wouldn't be surprised if
char16_tgets pushed back when this reaches LEWG. The motivation for it basically boils down to "well, if we're doing the other Unicode types, might as well." That's not exactly compelling when it adds more overloads to an already enormous surface area.The SG16 issue has been open since 2018. Eight years from "paper needed" label to R1. Committee speed is something else.
The function-template approach is fine, but the result type situation is going to confuse people. You end up with
to_chars_result,u8to_chars_result,u16to_chars_result,u32to_chars_result,wto_chars_result, and then the same five forfrom_chars. Ten new types because ABI prevents templating the existing ones.The
to_chars_result_t<T>alias helps but it's the kind of thing that makes teachingcharconvharder. "What doesto_charsreturn?" "Depends on the character type. Let me show you the alias template."Best part of the paper is the implementation survey. All three major standard libraries already have the conversion logic in internal templates. This is essentially just exposing what already exists with a public API. The
static_cast<charT>('+')fix for libc++ is about as complex as it gets.The real problem isn't that
to_charsdoesn't supportchar8_t. The real problem is that nothing in the standard library acceptschar8_tin a useful way. You can't construct astd::stringfrom au8literal without a cast. You can't passu8"hello"tostd::cout. Addingchar8_ttocharconvis nice but it's like installing a new faucet in a house that has no plumbing.This is the plumbing. The paper literally says
char8_tto_charsis a prerequisite forchar8_tstd::formatwhich is a prerequisite forchar8_tstd::print. You have to start somewhere.