This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
function_refSection: 22.10.17.1 [func.wrap.general] Status: New Submitter: Tomasz Kamiński Opened: 2025-05-15 Last modified: 2025-10-27
Priority: 2
View all issues with New status.
Discussion:
Addresses RU-220Currently the wording in 22.10.17.1 [func.wrap.general] allows implementation to avoid double indirection when constructing owning functions wrappers from another one:
-2- Let
tbe an object of a type that is a specialization offunction,copyable_function, ormove_only_function, such that the target objectxofthas a type that is a specialization offunction,copyable_function, ormove_only_function. Each argument of the invocation ofxevaluated as part of the invocation oftmay alias an argument in the same position in the invocation oftthat has the same type, even if the corresponding parameter is not of reference type.
However, the wording does not cover a function_ref, disallowing implementation to perform
this optimization when signatures are compatible, for example:
std::function_ref<void() noexcept> f1(ptr); std::function_ref<void()> f1(f2);
We should include function_ref in the list. Note that this allows, but does not require,
an implementation to perform such an optimization. As a consequence, it is acceptable
to specify the allowance for all combinations of polymorphic wrappers, even for creating an
owning wrapper from a non-owning one, where implementing such an optimization may not be possible.
Previous resolution [SUPERSEDED]:
This wording is relative to N5008.
Modify 22.10.17.1 [func.wrap.general] as indicated:
-2- Let
tbe an object of a type that is a specialization offunction,copyable_function,ormove_only_function, orfunction_ref, such that the target objectxofthas a type that is a specialization offunction,copyable_function,ormove_only_function, orfunction_ref. Each argument of the invocation ofxevaluated as part of the invocation oftmay alias an argument in the same position in the invocation oftthat has the same type, even if the corresponding parameter is not of reference type.
[2024-05-21; Tomasz's comment and upates proposed resolution]
After implementing double indirection avoidance in the libstdc++, I have realized that above wording change is insufficient to cover all user observable effects of the change. Revelant quote from the Avoid double indirection in function_ref from libstdc++ mailing lists:
To avoidance of double indirection requires that constructed
function_ref, refers directly to the target function of the source, instead of source, and this is visible after the assigment:void foo() noexcept; void bar() noexcept; std::function_ref<void() noexcept> sr(&foo); std::function_ref<void()> dr(sr); dr(); // callsfooregardless of implementation sr = &bar; sr(); // callsbardr(); // still callsfooif we avoid indirection, // callsbarif we do notSimilary for
move_only_function/copyable_functionsource:std::move_only_function<void()> sm; std::function_ref<void()> dm(sm); dm(); // UB becausesmis empty sm = &foo; dm(); // remains UB if we avoid indirection, // callsbarif we do not.While we may want to allow skipping indirection for function_ref, as this produces same behavior as in case for copy constructor (matching signatures):
void foo() noexcept; void bar() noexcept; std::function_ref<void() noexcept> sr(&foo); std::function_ref<void() noexcept> dr(sr); // copy-cosntructor dr(); // callsfooregardless of implementation sr = &bar; sr(); // callsbardr(); // still callsfooif we avoid indirectionI do not think this is acceptable for
move_only_function. …Note that for the same reason, implementations are not free to avoid dangling when constructing
function_reffromreference_wrapper:auto srw = std::ref(&foo); std::function_ref<void()> drw(srw); drw(); // callsfoosrw = std::ref(&bar); drw(); // callsfooif we unwrap referenc wrapper, // callsbarotherwise.Note that this is limited to
function_refdue reference nature of this wrapper.
The updated resolution allows indirection but making it unspecified if
function_ref constructed from other function_ref specialization,
will refer to source object or its target.
[2025-10-21; Reflector poll.]
Set priority to 2 after reflector poll.
Strong oposition to making it unspecified whether function_ref constructed from
other function_ref will reference source object or its target directly.
Proposed resolution:
This wording is relative to N5008.
Modify 22.10.17.1 [func.wrap.general] as indicated:
-2- Let
tbe an object of a type that is a specialization offunction,copyable_function,ormove_only_function, orfunction_ref, such that the target objectxofthas a type that is a specialization offunction,copyable_function,ormove_only_function, orfunction_ref. Each argument of the invocation ofxevaluated as part of the invocation oftmay alias an argument in the same position in the invocation oftthat has the same type, even if the corresponding parameter is not of reference type.
Modify 22.10.17.6.3 [func.wrap.ref.ctor] as indicated:
template<class F> constexpr function_ref(F&&) noexcept;[…]-7- Effects: Initializes
bound-entitywithaddressof(f)andthunk-ptrwith the address of a functionthunksuch thatthunk(bound-entity, call-args...)is expression-equivalent (3.22 [defns.expression.equivalent]) toinvoke_r<R>(static_cast<cv T&>(f), call-args...).-?- Remarks: If
remove_cveref_t<F>is a specialization offunction_refan implementation may initializebound-entitywithbound-entityoff. [Example::void f1() noexcept; void f2() noexcept; function_ref<void() noexcept> r1(&r1); function_ref<void()> r2(r1); r1 = &f2; f2(); // it is unspecified iff1orf2is invoked— end example]