2348. charT('1') is not the wide equivalent of '1'

Section: 23.9.2 [template.bitset], 30.7.8 [quoted.manip] Status: Open Submitter: Zhihao Yuan Opened: 2013-12-02 Last modified: 2016-02-10

Priority: 3

View all other issues in [template.bitset].

View all issues with Open status.

Discussion:

Example: char16_t('1') != u'1' is possible.

The numeric value of char16_t is defined to be Unicode code point, which is same to the ASCII value and UTF-8 for 7-bit chars. However, char is not guaranteed to have an encoding which is compatible with ASCII. For example, '1' in EBCDIC is 241.

I found three places in the standard casting narrow char literals: bitset::bitset, bitset::to_string and quoted.

PJ confirmed this issue and says he has a solution used in their <filesystem> implementation, and he may want to propose it to the standard.

The solution in my mind, for now, is to make those default arguments magical, where the "magic" can be implemented with a C11 _Generic selection (works in clang):

#define _G(T, literal) _Generic(T{}, \
      char: literal, \
      wchar_t: L ## literal, \
      char16_t: u ## literal, \
      char32_t: U ## literal)

  _G(char16_t, '1') == u'1'

[Lenexa 2015-05-05: Move to Open]

Ask for complete PR (need quoted, to string, et al.)

Will then take it up again

Expectation is that this is correct way to fix this

Proposed resolution:

This wording is relative to N3797.

[Drafting note: This is a sample wording fixing only one case; I'm just too lazy to copy-paste it before we discussed whether the solution is worth and sufficient (for example, should the other `charT`s like `unsigned char` just don't compile without supplying those arguments? I hope so). — end drafting note]
  1. Modify 23.9.2 [template.bitset] p1, class template bitset synopsis, as indicated:

    namespace std {
      template <size_t N> class bitset {
      public:
        […]
        template<class charT, class traits, class Allocator>
          explicit bitset(
            const basic_string<charT,traits,Allocator>& str,
            typename basic_string<charT,traits,Allocator>::size_type pos = 0,
            typename basic_string<charT,traits,Allocator>::size_type n =
              basic_string<charT,traits,Allocator>::npos,
              charT zero = charT('0')see below, charT one = charT('1')see below);
         […]
      };
      […]
    }
    
  2. Modify 23.9.2.1 [bitset.cons] as indicated:

    template<class charT, class traits, class Allocator>
    explicit 
    bitset(const basic_string<charT, traits, Allocator>& str,
           typename basic_string<charT, traits, Allocator>::size_type pos = 0,
           typename basic_string<charT, traits, Allocator>::size_type n =
             basic_string<charT, traits, Allocator>::npos,
             charT zero = charT('0')see below, charT one = charT('1')see below);
    

    -?- The default values of zero and one compare equal to the character literals 0 and 1 of type charT, respectively.

    -3- Requires:: pos <= str.size().

    […]