Constructor of move_only_function with empty ref-qualifier is over-constrained
Zhihao Yuan

Created on 2022-02-27.00:00:00 last changed 2 months ago


Date: 2022-03-04.14:33:52

Proposed resolution:

This wording is relative to N4901.

  1. Modify [func.wrap.move.ctor] as indicated:

    template<class VT>
      static constexpr bool is-callable-from = see below;

    -1- If noex is true, is-callable-from<VT> is equal to:

    is_nothrow_invocable_r_v<R, VT cv ref, ArgTypes...> &&
    is_nothrow_invocable_r_v<R, VT inv-quals, ArgTypes...>

    Otherwise, is-callable-from<VT> is equal to:

    is_invocable_r_v<R, VT cv ref, ArgTypes...> &&
    is_invocable_r_v<R, VT inv-quals, ArgTypes...>
Date: 2022-03-15.00:00:00

[ 2022-03-04; Reflector poll ]

Set priority to 2 after reflector poll. Probably needs a paper for LEWG.

Date: 2022-02-27.00:00:00

The following test compiles and holds:

struct X
  int operator()() & { return 1; }  // #1
  int operator()() && { return 2; } // #2

using T = move_only_function<int()>;
assert(T(X{})() == 1);

In other words, #2 is never used. But if you really remove #2, the code doesn't compile.

The change was introduced between P0288R5 and P0288R6, with an intention (assumed) to require move_only_function<R(Args...) cv> erasing callable objects with operator() without ref-qualifiers. But the actual outcome outlawed programs that were valid when using std::function.

It also outlaws future programs such as

T x = [captures](this auto&) { return ...; }

where declaring this auto&& without forwarding only to satisfy move_only_function's constraints would be strange.

Date User Action Args
2022-03-04 14:33:52adminsetmessages: + msg12403
2022-02-27 10:34:17adminsetmessages: + msg12387
2022-02-27 00:00:00admincreate