3977. constexpr and noexcept for operators for bitmask types

Section: 16.3.3.3.3 [bitmask.types] Status: New Submitter: Jiang An Opened: 2023-08-19 Last modified: 2023-09-24 09:43:08 UTC

Priority: Not Prioritized

View other active issues in [bitmask.types].

View all other issues in [bitmask.types].

View all issues with New status.

Discussion:

Currently, no operator in 16.3.3.3.3 [bitmask.types]/2 is specified as noexcept, and the compound assignment operators are not specified as constexpr.

Implementations are divergent on this. E.g., MSVC STL consistently marks them constexpr and noexcept (given MSVC STL doesn't support pre-C++14 modes), while libstdc++'s compound assignment operators for match_flag_type are constexpr since C++14 but lack noexcept, and the operators for launch are noexcept but not constexpr.

I think it's better to ensure more consistency be integer types and non-integer bitmask types, i.e., require the compound assignment operators to be constexpr (only available in C++14 and later) and all operators to be noexcept.

Proposed resolution:

This wording is relative to N4958.

  1. Modify 16.3.3.3.3 [bitmask.types] as indicated:

    -2- The bitmask type bitmask can be written:

    // For exposition only.
    // int_type is an integral type capable of representing all values of the bitmask type.
    enum bitmask : int_type {
      V0 = 1 << 0, V1 = 1 << 1, V2 = 1 << 2, V3 = 1 << 3, …
    };
    
    inline constexpr bitmask C0(V0);
    inline constexpr bitmask C1(V1);
    inline constexpr bitmask C2(V2);
    inline constexpr bitmask C3(V3);
    
    […]
    
    constexpr bitmask operator&(bitmask X, bitmask Y) noexcept {
      return static_cast<bitmask>(
        static_cast<int_type>(X) & static_cast<int_type>(Y));
    }
    constexpr bitmask operator|(bitmask X, bitmask Y) noexcept {
      return static_cast<bitmask>(
        static_cast<int_type>(X) | static_cast<int_type>(Y));
    }
    constexpr bitmask operator^(bitmask X, bitmask Y) noexcept {
      return static_cast<bitmask>(
        static_cast<int_type>(X) ^ static_cast<int_type>(Y));
    }
    constexpr bitmask operator~(bitmask X) noexcept {
      return static_cast<bitmask>(~static_cast<int_type>(X));
    }
    constexpr bitmask& operator&=(bitmask& X, bitmask Y) noexcept {
      X = X & Y; return X;
    }
    constexpr bitmask& operator|=(bitmask& X, bitmask Y) noexcept {
      X = X | Y; return X;
    }
    constexpr bitmask& operator^=(bitmask& X, bitmask Y) noexcept {
      X = X ^ Y; return X;
    }