bitset::reference should be const-assignableSection: 22.9.2 [template.bitset] Status: New Submitter: Arthur O'Dwyer Opened: 2024-12-21 Last modified: 2025-02-07
Priority: 3
View other active issues in [template.bitset].
View all other issues in [template.bitset].
View all issues with New status.
Discussion:
LWG 3638, 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).
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:
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;
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.
[2025-02-07; Reflector poll]
Set priority to 3 after reflector poll.
"Just const-quality the existing assignment operators."
"Would need to change the return type (breaking) or use const_cast (weird)."
"And it would be needlessly inconsistent with vector<bool>::reference."
"The swap part belongs in LWG 3638."
Previous resolution [SUPERSEDED]:
This wording is relative to N5001.
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; }; […] }; […] }
[2025-02-07; Jonathan provides improved wording]
Moved swap changes to LWG 3638.
Proposed resolution:
This wording is relative to N5001.
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();
};
[…]
};
[…]
}