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_ref
Section: 22.10.17.1 [func.wrap.general] Status: New Submitter: Tomasz Kamiński Opened: 2025-05-15 Last modified: 2025-05-26
Priority: Not Prioritized
View all issues with New status.
Discussion:
Currently 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
t
be an object of a type that is a specialization offunction
,copyable_function
, ormove_only_function
, such that the target objectx
oft
has a type that is a specialization offunction
,copyable_function
, ormove_only_function
. Each argument of the invocation ofx
evaluated as part of the invocation oft
may alias an argument in the same position in the invocation oft
that 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
t
be an object of a type that is a specialization offunction
,copyable_function
,ormove_only_function
, orfunction_ref
, such that the target objectx
oft
has a type that is a specialization offunction
,copyable_function
,ormove_only_function
, orfunction_ref
. Each argument of the invocation ofx
evaluated as part of the invocation oft
may alias an argument in the same position in the invocation oft
that 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(); // callsfoo
regardless of implementation sr = &bar; sr(); // callsbar
dr(); // still callsfoo
if we avoid indirection, // callsbar
if we do notSimilary for
move_only_function
/copyable_function
source:std::move_only_function<void()> sm; std::function_ref<void()> dm(sm); dm(); // UB becausesm
is empty sm = &foo; dm(); // remains UB if we avoid indirection, // callsbar
if 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(); // callsfoo
regardless of implementation sr = &bar; sr(); // callsbar
dr(); // still callsfoo
if 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_ref
fromreference_wrapper
:auto srw = std::ref(&foo); std::function_ref<void()> drw(srw); drw(); // callsfoo
srw = std::ref(&bar); drw(); // callsfoo
if we unwrap referenc wrapper, // callsbar
otherwise.Note that this is limited to
function_ref
due 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.
Proposed resolution:
This wording is relative to N5008.
Modify 22.10.17.1 [func.wrap.general] as indicated:
-2- Let
t
be an object of a type that is a specialization offunction
,copyable_function
,ormove_only_function
, orfunction_ref
, such that the target objectx
oft
has a type that is a specialization offunction
,copyable_function
,ormove_only_function
, orfunction_ref
. Each argument of the invocation ofx
evaluated as part of the invocation oft
may alias an argument in the same position in the invocation oft
that 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-entity
withaddressof(f)
andthunk-ptr
with the address of a functionthunk
such 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_ref
an implementation may initializebound-entity
withbound-entity
off
. [Example::void f1() noexcept; void f2() noexcept; function_ref<void() noexcept> r1(&r1); function_ref<void()> r2(r1); r1 = &f2; f2(); // it is unspecified iff1
orf2
is invoked— end example]