ICU supports customization of its internal code unit type, but char16_t is used by default, following ICU’s adoption of C++11.

Not quite... ICU supports customization of its code unit type for C APIs. Internally, and in C++ APIs, we switched to char16_t. And because that broke call sites, we mitigated where we could with overloads and shim classes.

This was all quite painful.

As for char8_t, I realize that you think the benefits outweigh the costs.
I asked some C++ experts about the potential for performance gains from better optimizations; one responded with a skeptical note.

If you do want a distinct type, why not just standardize on uint8_t? Why does it need to be a new type that is distinct from that, too?

Best regards,
markus