Date: Wed, 10 Sep 2025 19:39:11 +0000
I have also seen similar “creative” uses of std::string_view in place of span. Even in C++20 and when span is available, because of “legacy reasons”. The solution is to refactor as you go…
But I agree with the sentiment that char_traits is irredeemably bad, there is however no need to deprecate, if one is available then it is used (for backwards compatibility so that 1 person in the world is happy we didn’t break their code) and if one isn’t available then that is also fine and a “default behavior” is assumed. I believe this may already be the case in practice in certain implementations even if not in theory.
With exception for whatever algorithm uses eof facilities, those can just be made deprecated if that’s how you are determining the end of streams, I’m ok with those just flat out not working.
From: SG16 <sg16-bounces_at_[hidden]> On Behalf Of Eddie Nolan via SG16
Sent: Wednesday, September 10, 2025 20:49
To: sg16_at_[hidden]
Cc: Eddie Nolan <eddiejnolan_at_[hidden]om>; Corentin <corentin.jabot_at_[hidden]>; Tom Honermann <tom_at_[hidden]>
Subject: Re: [isocpp-sg16] Agenda for the 2025-09-10 SG16 meeting
Hi,
I have an anecdote about char_traits; I’m not sure how it should influence the discussion but I hope it adds information.
Most of the codebase at my company must support a minimum standard version of C++17 and therefore lacks std::span, but frequently needs to pass around slices of byte buffers containing e.g. packets. As a workaround, some of our developers used std::string_view instead of std::span, instantiating types like std::string_view<unsigned char> and std::string_view<std::uint8_t>, which had happened to work for a while, although the standard only guarantees availability of char_traits for char/wchar_t/charN_t.
When we updated our Clang CI to use libc++ 18, we began getting deprecation warnings for these uses of std::string_view. One of the solutions that was floated was to implement our own char_traits classes for unsigned char and std::uint8_t.
However, after some debate, we more sensibly refactored each of those uses of std::string_view to use boost::span instead.
I bet that many of the codebases with custom char_traits are working around similar non-semantic uses of std::string_view in place of std::span.
- Eddie
On Tue, Sep 9, 2025 at 4:35 PM Tom Honermann via SG16 <sg16_at_[hidden]<mailto:sg16_at_[hidden]>> wrote:
On 9/9/25 3:50 PM, Tom Honermann via SG16 wrote:
SG16 will hold a meeting tomorrow, Wednesday, September 10th, at 19:30 UTC (timezone conversion<https://www.timeanddate.com/worldclock/converter.html?iso=20250910T193000&p1=1440&p2=tz_pdt&p3=tz_mdt&p4=tz_cdt&p5=tz_edt&p6=tz_cest>).
If you need a .ics file to import into your calendar, you can download it here<https://documents.isocpp.org/remote.php/dav/public-calendars/R7imgS2LJD9xfeWN/94A3D3A0-70B9-4847-935F-9453DB2BB216.ics?export>.
The agenda is:
* P3681R0: char_traits: Stop the bleeding!<https://wg21.link/p3681r0>
* P3672R0: On Windows, Systems APIs, Text Encodings, and Pragmatism<https://wg21.link/p3672r0>.
P3681R0 is Corentin's attempt to dissuade the continued appearance of std::char_traits in new standard library features and comes to us following discussions of P3655 (std::zstring_view)<https://wg21.link/p3655>. SG16 discussed P3655R0 during the 2025-04-23 SG16 meeting<https://wiki.edg.com/bin/view/Wg21telecons2025/SG16Teleconference2025-04-23> where we took the following poll.
Poll 1: P3655R0: No objection to use of std::char_traits for consistency and compatibility with std::string_view.
* Attendees: 8 (no abstentions)
*
SF
F
N
A
SA
7
1
0
0
0
* Strong consensus.
Corentin was not present for that meeting, so this paper does not represent a change of opinion from him, but rather a request to reconsider that poll and to perhaps establish a policy related to std::char_traits for future work. The paper explicitly addresses the possibility of custom char trait types and how such existing use with std::basic_string would impact convertibility to std::zstring_view.
I performed a github code search to try to get a better sense of how often, and for what purpose, programmers define their own char_traits-like types. To find such cases, I searched for one of the more esoteric member function names required to satisfy the character traits requirements<https://eel.is/c++draft/char.traits.require>; eq_int_type().
* blackboxwm defines its own specialization of std::char_traits for its bt::Uchar (unsigned int) type<https://github.com/bbidulock/blackboxwm/blob/22c0762237d08d04dedd13bcfc4a442a7e5a634d/lib/Unicode.hh#L79-L167>.
* libxmldiff defines its own specialization of std::char_traits for its xmlChar type<https://github.com/rpeyron/libxmldiff/blob/673930108f98e74d4b46e5078569efb7a5e2f8d7/src/lx2_str.h#L103-L190>.
* data-macross-libzmq defines its own specialization of std::char_traits for unsigned char<https://github.com/jampp/data-macross-libzmq/blob/cca67fdd1b3030ce4daeccc653c71b0671e5ed36/src/blob.hpp#L43-L126>.
* TheVeryDarkness/MyLibrary defines its own specialization of std::char_traits for its UniChar class type<https://github.com/TheVeryDarkness/MyLibrary/blob/4477dce87a332014de5f11bd86f1006dff802242/Unicode.h#L65-L117>.
* cryptagram defines a string16_char_traits type for its char16 (unsigned short) type<https://github.com/prglab/cryptagram/blob/85e7ddcb3d4c0021495da10c63a0640f8213eed9/experimental/lib/src/string16.h#L56-L123>.
* ogc defines a traits_nocase type that behaves as a case-insensitive variant of std::char_traits<char><https://github.com/norcalli/ogc/blob/3df8fc652c8ce47833d2eba9a5badc1013d2dde0/string-utils.h#L92-L111>.
* coinflex-exchange/common defines a ci::char_traits template that behaves as a case-insensitive variant of std::char_traits<CharT><https://github.com/coinflex-exchange/common/blob/a1967f12b5963a286fc4381f388d67d16845bdf7/ci.h#L22-L40>.
* tinyexpr-plusplus defines a case_insensitive_char_traits that behaves as a case insensitive character traits type for char<https://github.com/aiekick/tinyexpr-plusplus/blob/73bdf85e1610a1424e76881bdd4ec941350832a5/tinyexpr.h#L118-L237>.
These are a few of the results<https://github.com/search?q=eq_int_type&type=code> that showed up on the first page of the search. The search claimed 20.2k results. I didn't look further.
Tom.
P3672R0 is an opinion paper that discusses encoding expectations on different platforms, the consequences of command line arguments and file paths that are not well-formed text, the degree to which we should care about such content, and the impact such complexity can, and should, have on standard library features and interfaces. Thoughts on these issues has implications for P3474R0 (std::arguments)<https://wg21.link/p3474r0>; a paper we last discussed during the 2025-04-09 SG16 meeting<https://wiki.edg.com/bin/view/Wg21telecons2025/SG16Teleconference2025-04-09> and which is currently awaiting a new revision<https://github.com/cplusplus/papers/issues/2128#issuecomment-2791081002>.
Tom.
--
SG16 mailing list
SG16_at_[hidden]<mailto:SG16_at_[hidden]>
https://lists.isocpp.org/mailman/listinfo.cgi/sg16
Link to this post: http://lists.isocpp.org/sg16/2025/09/4606.php
But I agree with the sentiment that char_traits is irredeemably bad, there is however no need to deprecate, if one is available then it is used (for backwards compatibility so that 1 person in the world is happy we didn’t break their code) and if one isn’t available then that is also fine and a “default behavior” is assumed. I believe this may already be the case in practice in certain implementations even if not in theory.
With exception for whatever algorithm uses eof facilities, those can just be made deprecated if that’s how you are determining the end of streams, I’m ok with those just flat out not working.
From: SG16 <sg16-bounces_at_[hidden]> On Behalf Of Eddie Nolan via SG16
Sent: Wednesday, September 10, 2025 20:49
To: sg16_at_[hidden]
Cc: Eddie Nolan <eddiejnolan_at_[hidden]om>; Corentin <corentin.jabot_at_[hidden]>; Tom Honermann <tom_at_[hidden]>
Subject: Re: [isocpp-sg16] Agenda for the 2025-09-10 SG16 meeting
Hi,
I have an anecdote about char_traits; I’m not sure how it should influence the discussion but I hope it adds information.
Most of the codebase at my company must support a minimum standard version of C++17 and therefore lacks std::span, but frequently needs to pass around slices of byte buffers containing e.g. packets. As a workaround, some of our developers used std::string_view instead of std::span, instantiating types like std::string_view<unsigned char> and std::string_view<std::uint8_t>, which had happened to work for a while, although the standard only guarantees availability of char_traits for char/wchar_t/charN_t.
When we updated our Clang CI to use libc++ 18, we began getting deprecation warnings for these uses of std::string_view. One of the solutions that was floated was to implement our own char_traits classes for unsigned char and std::uint8_t.
However, after some debate, we more sensibly refactored each of those uses of std::string_view to use boost::span instead.
I bet that many of the codebases with custom char_traits are working around similar non-semantic uses of std::string_view in place of std::span.
- Eddie
On Tue, Sep 9, 2025 at 4:35 PM Tom Honermann via SG16 <sg16_at_[hidden]<mailto:sg16_at_[hidden]>> wrote:
On 9/9/25 3:50 PM, Tom Honermann via SG16 wrote:
SG16 will hold a meeting tomorrow, Wednesday, September 10th, at 19:30 UTC (timezone conversion<https://www.timeanddate.com/worldclock/converter.html?iso=20250910T193000&p1=1440&p2=tz_pdt&p3=tz_mdt&p4=tz_cdt&p5=tz_edt&p6=tz_cest>).
If you need a .ics file to import into your calendar, you can download it here<https://documents.isocpp.org/remote.php/dav/public-calendars/R7imgS2LJD9xfeWN/94A3D3A0-70B9-4847-935F-9453DB2BB216.ics?export>.
The agenda is:
* P3681R0: char_traits: Stop the bleeding!<https://wg21.link/p3681r0>
* P3672R0: On Windows, Systems APIs, Text Encodings, and Pragmatism<https://wg21.link/p3672r0>.
P3681R0 is Corentin's attempt to dissuade the continued appearance of std::char_traits in new standard library features and comes to us following discussions of P3655 (std::zstring_view)<https://wg21.link/p3655>. SG16 discussed P3655R0 during the 2025-04-23 SG16 meeting<https://wiki.edg.com/bin/view/Wg21telecons2025/SG16Teleconference2025-04-23> where we took the following poll.
Poll 1: P3655R0: No objection to use of std::char_traits for consistency and compatibility with std::string_view.
* Attendees: 8 (no abstentions)
*
SF
F
N
A
SA
7
1
0
0
0
* Strong consensus.
Corentin was not present for that meeting, so this paper does not represent a change of opinion from him, but rather a request to reconsider that poll and to perhaps establish a policy related to std::char_traits for future work. The paper explicitly addresses the possibility of custom char trait types and how such existing use with std::basic_string would impact convertibility to std::zstring_view.
I performed a github code search to try to get a better sense of how often, and for what purpose, programmers define their own char_traits-like types. To find such cases, I searched for one of the more esoteric member function names required to satisfy the character traits requirements<https://eel.is/c++draft/char.traits.require>; eq_int_type().
* blackboxwm defines its own specialization of std::char_traits for its bt::Uchar (unsigned int) type<https://github.com/bbidulock/blackboxwm/blob/22c0762237d08d04dedd13bcfc4a442a7e5a634d/lib/Unicode.hh#L79-L167>.
* libxmldiff defines its own specialization of std::char_traits for its xmlChar type<https://github.com/rpeyron/libxmldiff/blob/673930108f98e74d4b46e5078569efb7a5e2f8d7/src/lx2_str.h#L103-L190>.
* data-macross-libzmq defines its own specialization of std::char_traits for unsigned char<https://github.com/jampp/data-macross-libzmq/blob/cca67fdd1b3030ce4daeccc653c71b0671e5ed36/src/blob.hpp#L43-L126>.
* TheVeryDarkness/MyLibrary defines its own specialization of std::char_traits for its UniChar class type<https://github.com/TheVeryDarkness/MyLibrary/blob/4477dce87a332014de5f11bd86f1006dff802242/Unicode.h#L65-L117>.
* cryptagram defines a string16_char_traits type for its char16 (unsigned short) type<https://github.com/prglab/cryptagram/blob/85e7ddcb3d4c0021495da10c63a0640f8213eed9/experimental/lib/src/string16.h#L56-L123>.
* ogc defines a traits_nocase type that behaves as a case-insensitive variant of std::char_traits<char><https://github.com/norcalli/ogc/blob/3df8fc652c8ce47833d2eba9a5badc1013d2dde0/string-utils.h#L92-L111>.
* coinflex-exchange/common defines a ci::char_traits template that behaves as a case-insensitive variant of std::char_traits<CharT><https://github.com/coinflex-exchange/common/blob/a1967f12b5963a286fc4381f388d67d16845bdf7/ci.h#L22-L40>.
* tinyexpr-plusplus defines a case_insensitive_char_traits that behaves as a case insensitive character traits type for char<https://github.com/aiekick/tinyexpr-plusplus/blob/73bdf85e1610a1424e76881bdd4ec941350832a5/tinyexpr.h#L118-L237>.
These are a few of the results<https://github.com/search?q=eq_int_type&type=code> that showed up on the first page of the search. The search claimed 20.2k results. I didn't look further.
Tom.
P3672R0 is an opinion paper that discusses encoding expectations on different platforms, the consequences of command line arguments and file paths that are not well-formed text, the degree to which we should care about such content, and the impact such complexity can, and should, have on standard library features and interfaces. Thoughts on these issues has implications for P3474R0 (std::arguments)<https://wg21.link/p3474r0>; a paper we last discussed during the 2025-04-09 SG16 meeting<https://wiki.edg.com/bin/view/Wg21telecons2025/SG16Teleconference2025-04-09> and which is currently awaiting a new revision<https://github.com/cplusplus/papers/issues/2128#issuecomment-2791081002>.
Tom.
--
SG16 mailing list
SG16_at_[hidden]<mailto:SG16_at_[hidden]>
https://lists.isocpp.org/mailman/listinfo.cgi/sg16
Link to this post: http://lists.isocpp.org/sg16/2025/09/4606.php
Received on 2025-09-10 19:39:17