Title
Useless default constructors for bit reference types
Status
voting
Section
[template.bitset.general] [vector.bool.pspc]
Submitter
Jonathan Wakely

Created on 2024-08-21.00:00:00 last changed yesterday

Messages

Date: 2024-09-18.22:28:54

Proposed resolution:

This wording is relative to N4988.

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

    namespace std {
      template<size_t N> class bitset {
      public:
        // bit reference
        class reference {
          friend class bitset;
          constexpr reference() noexcept;
    
        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 bool operator~() const noexcept;                  // flips the bit
          constexpr operator bool() const noexcept;                   // for x = b[i];
          constexpr reference& flip() noexcept;                       // for b[i].flip();
        };
    
  2. Modify [vector.bool.pspc], vector<bool, Allocator> synopsis, as indicated:

    namespace std {
      template<class Allocator>
      class vector<bool, Allocator> {
      public:
        // types
        […]
        // bit reference
        class reference {
          friend class vector;
          constexpr reference() noexcept;
    
        public:
          constexpr reference(const reference&) = default;
          constexpr ~reference();
          constexpr operator bool() const noexcept;
          constexpr reference& operator=(bool x) noexcept;
          constexpr reference& operator=(const reference& x) noexcept;
          constexpr const reference& operator=(bool x) const noexcept;
          constexpr void flip() noexcept;   // flips the bit
        };
    
Date: 2024-09-15.00:00:00

[ 2024-09-18; Reflector poll ]

Set status to Tentatively Ready after eight votes in favour during reflector poll.

Date: 2024-08-22.09:34:34

The standard shows a private default constructor for bitset<N>::reference but does not define its semantics, and nothing in the spec refers to it. It was present in C++98, then in C++11 it got `noexcept` added to it, and in C++23 it was made `constexpr` by P2417R2. That's quite a lot of churn for an unusuable member function with no definition.

In libstdc++ it's declared as private, but never defined. In libc++ it doesn't exist at all. In MSVC it is private and defined (and presumably used somewhere). There's no reason for the standard to declare it. Implementers can define it as private if they want to, or not. The spec doesn't need to say anything for that to be true. We can also remove the friend declaration, because implementers know how to do that too.

I suspect it was added as private originally so that it didn't look like `reference` should have an implicitly-defined default constructor, which would have been the case in previous standards with no other constructors declared. However, C++20 added reference(const reference&) = default; which suppresses the implicit default constructor, so declaring the default constructor as private is now unnecessary.

Jiang An pointed out in an editorial pull request that vector<bool, Alloc>::reference has exactly the same issue.

History
Date User Action Args
2024-11-19 16:09:07adminsetstatus: ready -> voting
2024-09-18 22:28:54adminsetmessages: + msg14383
2024-09-18 22:28:54adminsetstatus: new -> ready
2024-08-21 14:36:20adminsetmessages: + msg14325
2024-08-21 00:00:00admincreate