Title
The requirements on literal type in [concept.swappable] should be removed
Status
new
Section
[concept.swappable]
Submitter
Jiang An

Created on 2024-01-20.00:00:00 last changed 1 month ago

Messages

Date: 2024-03-15.13:46:33

Proposed resolution:

This wording is relative to N4971.

  1. Modify [concept.swappable] as indicated:

    -2- The name ranges::swap denotes a customization point object ([customization.point.object]). The expression ranges::swap(E1, E2) for subexpressions E1 and E2 is expression-equivalent to an expression S determined as follows:

    1. (2.1) — […]

    2. (2.2) — […]

    3. (2.3) — Otherwise, if E1 and E2 are lvalues of the same type T that models move_constructible<T> and assignable_from<T&, T>, S is an expression that exchanges the denoted values. S is a constant expression if

      1. (2.3.1) — T is a literal type ([basic.types.general]),

      2. (2.3.2) — both E1 = std::move(E2) and E2 = std::move(E1) are constant subexpressions ([defns.const.subexpr]), and

      3. (2.3.3) — the full-expressions of the initializers in the declarations

        T t1(std::move(E1));
        T t2(std::move(E2));
        

        are constant subexpressions.

      noexcept(S) is equal to is_nothrow_move_constructible_v<T> && is_nothrow_move_assignable_v<T>.

    4. (2.4) — Otherwise, ranges::swap(E1, E2) is ill-formed.

    […]

Date: 2024-03-15.00:00:00

[ 2024-03-15; Reflector poll ]

Set priority to 4 after reflector poll.

Concerned about [expr.const]/5.16 (can only modify non-volatile lvalues of literal type in constant expressions). Unable see a non-contrived case where this issue matters.

N.B. ranges::swap needs the "reified object" treatment; the repetitions of `E1` and `E2` are not pure textual repetitions of the argument expressions.

Can we just eliminate all uses of "literal type"?

Wouldn't we still require a constexpr destructor?

Date: 2024-01-20.00:00:00

[concept.swappable] bullet (2.3.1) currently requires T to be a literal type in order to make the swapping expression a constant expression in that case. The requirement was likely automatically enforced by the core language rules in C++20 and thus essentially redundant.

However, as P2448R2 relaxed the restrictions on constexpr functions, it seems that the swapping expression can be a constant expression even if T is not a literal type.

E.g. the following program is accepted by GCC/libstdc++ in C++23 mode (demo).

#include <concepts>

struct NonLiteral {
  NonLiteral() {} // non-constexpr
  constexpr NonLiteral(const NonLiteral&) noexcept {};
  constexpr NonLiteral& operator=(const NonLiteral&) noexcept { return *this; };
};

int main()
{
  NonLiteral x;
  static_assert((std::ranges::swap(x, x), true));
}

IMO there's no good reason to additionally require literal types since C++23, which would complicate implementations.

History
Date User Action Args
2024-03-15 13:46:33adminsetmessages: + msg14013
2024-01-21 07:32:54adminsetmessages: + msg13925
2024-01-20 00:00:00admincreate