This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

4187. bitset::reference should be const-assignable

Section: 22.9.2 [template.bitset] Status: New Submitter: Arthur O'Dwyer Opened: 2024-12-21 Last modified: 2024-12-22

Priority: Not Prioritized

View other active issues in [template.bitset].

View all other issues in [template.bitset].

View all issues with New status.

Discussion:

LWG 3638(i), which proposes changes to vector<bool>::reference, is related. Should vector<bool>::reference and bitset<N>::reference behave differently in any respect? I think there's no good reason for them to behave differently, and good technical incentives to permit them to behave the same. We already have implementation divergence: libc++ makes bitset::reference const-assignable, whereas libstdc++ and MS STL do not. This means that libc++'s bitset::reference successfully avoids false positives from Arthur's proposed -Wassign-to-class-rvalue diagnostic, while libstdc++'s does not (See Godbolt).

The proposed resolution applies P2321's approach. We can't just insert const into the existing spec, because ABI. But also, since our goal is consistency with the post-P2321 vector<bool>::reference, we should do the same thing here as P2321, not invent anything novel.

Open questions related to the current P/R:

  1. LWG 3638 proposes to add these three swap overloads to vector<bool>::reference. Should we also, consistently, add them to bitset::reference? I think we should.

    friend constexpr void swap(reference x, reference y) noexcept;
    friend constexpr void swap(reference x, bool& y) noexcept;
    friend constexpr void swap(bool& x, reference y) noexcept;
    
  2. Both vector<bool>::reference and bitset::reference right now are specified with

    constexpr reference(const reference&) = default;
    

    which is meaningless because we don't know the data members of reference. So this isn't actually specifying that the constructor is trivial, let alone that it's noexcept. I think we should re-specify both types' copy constructors as simply constexpr and noexcept; and then if we want them to be trivial, we should say so in English prose.

Proposed resolution:

This wording is relative to N5001.

  1. Modify 22.9.2.1 [template.bitset.general] as indicated:

    namespace std {
      template<size_t N> class bitset {
      public:
        // bit reference
        class reference {
        public:
          constexpr reference(const reference&) = default;
          constexpr ~reference();
          constexpr reference& operator=(bool x) noexcept;           // for b[i] = x;
          constexpr reference& operator=(const reference&) noexcept; // for b[i] = b[j];
          constexpr const reference& operator=(bool x) const noexcept;
          constexpr bool operator~() const noexcept;                 // flips the bit
          constexpr operator bool() const noexcept;                  // for x = b[i];
          constexpr reference& flip() noexcept;                      // for b[i].flip();
          friend constexpr void swap(reference x, reference y) noexcept;
          friend constexpr void swap(reference x, bool& y) noexcept;
          friend constexpr void swap(bool& x, reference y) noexcept;      
        };
        […]
      };
      […]
    }