907. Bitset's immutable element retrieval is inconsistently defined

Section: 23.9.2.2 [bitset.members] Status: C++11 Submitter: Daniel Krügler Opened: 2008-09-26 Last modified: 2016-02-10

Priority: Not Prioritized

View all other issues in [bitset.members].

View all issues with C++11 status.

Discussion:

The current standard 14882::2003(E) as well as the current draft N2723 have in common a contradiction of the operational semantics of member function test 23.9.2.2 [bitset.members] p.56-58 and the immutable member operator[] overload 23.9.2.2 [bitset.members] p.64-66 (all references are defined in terms of N2723):

  1. bool test(size_t pos) const;
    

    Requires: pos is valid

    Throws: out_of_range if pos does not correspond to a valid bit position.

    Returns: true if the bit at position pos in *this has the value one.

  2. constexpr bool operator[](size_t pos) const;
    

    Requires: pos shall be valid.

    Throws: nothing.

    Returns: test(pos).

Three interpretations:

  1. The operator[] overload is indeed allowed to throw an exception (via test(), if pos corresponds to an invalid bit position) which does not leave the call frame. In this case this function cannot be a constexpr function, because test() is not, due to 8.6 [expr.const]/2, last bullet.
  2. The intend was not to throw an exception in test in case of an invalid bit position. There is only little evidence for this interpretation.
  3. The intend was that operator[] should not throw any exception, but that test has the contract to do so, if the provided bit position is invalid.

The problem became worse, because issue 720 recently voted into WP argued that member test logically must be a constexpr function, because it was used to define the semantics of another constexpr function (the operator[] overload).

Three alternatives are proposed, corresponding to the three bullets (A), (B), and (C), the author suggests to follow proposal (C).

Proposed alternatives:

  1. Remove the constexpr specifier in front of operator[] overload and undo that of member test (assuming 720 is accepted) in both the class declaration 23.9.2 [template.bitset]/1 and in the member description before 23.9.2.2 [bitset.members]/56 and before /64 to read:

    constexpr bool test(size_t pos) const;
    ..
    constexpr bool operator[](size_t pos) const;
    

    Change the throws clause of p. 65 to read:

    Throws: nothing out_of_range if pos does not correspond to a valid bit position.

  2. Replace the throws clause p. 57 to read:

    Throws: out_of_range if pos does not correspond to a valid bit position nothing.

  3. Undo the addition of the constexpr specifier to the test member function in both class declaration 23.9.2 [template.bitset]/1 and in the member description before 23.9.2.2 [bitset.members]/56, assuming that 720 was applied.

    constexpr bool test(size_t pos) const;
    

    Change the returns clause p. 66 to read:

    Returns: test(pos) true if the bit at position pos in *this has the value one, otherwise false.

[ Post Summit: ]

Lawrence: proposed resolutions A, B, C are mutually exclusive.

Recommend Review with option C.

[ Batavia (2009-05): ]

We agree with the proposed resolution. Move to Tentatively Ready.

Proposed resolution:

  1. […]
  2. […]
  3. Undo the addition of the constexpr specifier to the test member function in both class declaration 23.9.2 [template.bitset] p.1 and in the member description before 23.9.2.2 [bitset.members] p.56, assuming that 720 was applied.

    constexpr bool test(size_t pos) const;
    

    Change the returns clause p. 66 to read:

    Returns: test(pos) true if the bit at position pos in *this has the value one, otherwise false.