Created on 2025-05-15.00:00:00 last changed 2 weeks ago
Proposed resolution:
This wording is relative to N5008.
Modify [func.wrap.general] as indicated:
-2- Let t be an object of a type that is a specialization of function, copyable_function,
ormove_only_function, or function_ref, such that the target object x of t has a type that is a specialization of function, copyable_function,ormove_only_function, or function_ref. Each argument of the invocation of x evaluated as part of the invocation of t may alias an argument in the same position in the invocation of t that has the same type, even if the corresponding parameter is not of reference type.
Modify [func.wrap.ref.ctor] as indicated:
template<class F> constexpr function_ref(F&&) noexcept;[…]-7- Effects: Initializes bound-entity with addressof(f) and thunk-ptr with the address of a function thunk such that thunk(bound-entity, call-args...) is expression-equivalent ([defns.expression.equivalent]) to invoke_r<R>(static_cast<cv T&>(f), call-args...).
-?- Remarks: If remove_cveref_t<F> is a specialization of function_ref an implementation may initialize bound-entity with bound-entity of f. [Example::
void f1() noexcept; void f2() noexcept; function_ref<void() noexcept> r1(&r1); function_ref<void()> r2(r1); r1 = &f2; f2(); // it is unspecified if `f1` or `f2` is invoked— end example]
[ 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(); // calls `foo` regardless of implementation sr = &bar; sr(); // calls `bar` dr(); // still calls `foo` if we avoid indirection, // calls `bar` 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 because `sm` is empty sm = &foo; dm(); // remains UB if we avoid indirection, // calls `bar` 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(); // calls `foo` regardless of implementation sr = &bar; sr(); // calls `bar` dr(); // still calls `foo` 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 from reference_wrapper:
auto srw = std::ref(&foo); std::function_ref<void()> drw(srw); drw(); // calls `foo` srw = std::ref(&bar); drw(); // calls `foo` if we unwrap referenc wrapper, // calls `bar` 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.
Currently the wording in [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 of function, copyable_function, or move_only_function, such that the target object x of t has a type that is a specialization of function, copyable_function, or move_only_function. Each argument of the invocation of x evaluated as part of the invocation of t may alias an argument in the same position in the invocation of t 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.
This wording is relative to N5008.
Modify [func.wrap.general] as indicated:
-2- Let t be an object of a type that is a specialization of function, copyable_function,
ormove_only_function, or function_ref, such that the target object x of t has a type that is a specialization of function, copyable_function,ormove_only_function, or function_ref. Each argument of the invocation of x evaluated as part of the invocation of t may alias an argument in the same position in the invocation of t that has the same type, even if the corresponding parameter is not of reference type.
History | |||
---|---|---|---|
Date | User | Action | Args |
2025-05-21 10:16:44 | admin | set | messages: + msg14764 |
2025-05-18 11:32:02 | admin | set | messages: + msg14763 |
2025-05-15 00:00:00 | admin | create |