std::function
construction vs assignmentSection: 22.10.17.3.2 [func.wrap.func.con] Status: C++23 Submitter: Barry Revzin Opened: 2016-09-14 Last modified: 2023-11-22
Priority: 3
View all other issues in [func.wrap.func.con].
View all issues with C++23 status.
Discussion:
I think there's a minor defect in the std::function
interface. The constructor template is:
template <class F> function(F f);
while the assignment operator template is
template <class F> function& operator=(F&& f);
The latter came about as a result of LWG 1288, but that one was dealing with a specific issue that
wouldn't have affected the constructor. I think the constructor should also take f
by forwarding reference,
this saves a move in the lvalue/xvalue cases and is also just generally more consistent. Should just make sure
that it's stored as std::decay_t<F>
instead of F
.
[2019-07-26 Tim provides PR.]
Previous resolution [SUPERSEDED]:
This wording is relative to N4820.
Edit 22.10.17.3 [func.wrap.func], class template
function
synopsis, as indicated:namespace std { template<class> class function; // not defined template<class R, class... ArgTypes> { public: using result_type = R; // 22.10.17.3.2 [func.wrap.func.con], construct/copy/destroy function() noexcept; function(nullptr_t) noexcept; function(const function&); function(function&&) noexcept; template<class F> function(F&&); […] }; […] }Edit 22.10.17.3.2 [func.wrap.func.con] p7-11 as indicated:
template<class F> function(F&& f);
-7- Requires:LetF
shall be Cpp17CopyConstructibleFD
bedecay_t<F>
.-8-
Remarks: This constructor template shall not participate in overload resolution unlessConstraints:F
(8.1) —
is_same_v<FD, function>
isfalse
; and(8.2) —
FD
is Lvalue-Callable (22.10.17.3 [func.wrap.func]) for argument typesArgTypes...
and return typeR
.-?- Expects:
FD
meets the Cpp17CopyConstructible requirements.-9- Ensures:
!*this
if any of the following hold:
(9.1) —
f
is a null function pointer value.(9.2) —
f
is a null member pointer value.(9.3) —
F
is an instanceremove_cvref_t<F>
is a specialization of thefunction
class template, and!f
istrue
.-10- Otherwise,
*this
targetsa copy ofan object of typef
FD
direct-non-list-initialized withstd::move(f)
std::forward<F>(f)
. [Note: Implementations should avoid the use of dynamically allocated memory for small callable objects, for example, wheref
isrefers to an object holding only a pointer or reference to an object and a member function pointer. — end note]-11- Throws:
ShallDoes not throw exceptions whenf
FD
is a function pointer type or a specialization ofreference_wrapper
. Otherwise, may throw<T>
for someT
bad_alloc
or any exception thrown bythe initialization of the target object.F
’s copy or move constructor
[2020-11-01; Daniel comments and improves the wording]
The proposed wording should — following the line of Marshall's "Mandating" papers — extract from the Cpp17CopyConstructible precondition a corresponding Constraints: element and in addition to that the wording should replace old-style elements such as Expects: by the recently agreed on elements.
See also the related issue LWG 3493.Previous resolution [SUPERSEDED]:
This wording is relative to N4868.
Edit 22.10.17.3 [func.wrap.func], class template
function
synopsis, as indicated:namespace std { template<class> class function; // not defined template<class R, class... ArgTypes> { public: using result_type = R; // 22.10.17.3.2 [func.wrap.func.con], construct/copy/destroy function() noexcept; function(nullptr_t) noexcept; function(const function&); function(function&&) noexcept; template<class F> function(F&&); […] }; […] }Edit 22.10.17.3.2 [func.wrap.func.con] as indicated:
template<class F> function(F&& f);Let
-8- Constraints:FD
bedecay_t<F>
.
(8.1) —
is_same_v<remove_cvref_t<F>, function>
isfalse
,(8.2) —
FD
is Lvalue-Callable (22.10.17.3.1 [func.wrap.func.general]) for argument typesF
ArgTypes...
and return typeR
,(8.3) —
is_copy_constructible_v<FD>
istrue
, and(8.4) —
is_constructible_v<FD, F>
istrue
.-9- Preconditions:
-10- Postconditions:meets the Cpp17CopyConstructible requirements.
FFD!*this
if any of the following hold:
(10.1) —
f
is a null function pointer value.(10.2) —
f
is a null member pointer value.(10.3) —
F
is an instanceremove_cvref_t<F>
is a specialization of the function class template, and!f
istrue
.-11- Otherwise,
-12- Throws: Nothing if*this
targetsa copy ofan object of typef
FD
direct-non-list-initialized with.
std::move(f)std::forward<F>(f)is a specialization of
fFDreference_wrapper
or a function pointer type. Otherwise, may throwbad_alloc
or any exception thrown bythe initialization of the target object. -13- Recommended practice: Implementations should avoid the use of dynamically allocated memory for small callable objects, for example, whereF
's copy or move constructorf
isrefers to an object holding only a pointer or reference to an object and a member function pointer.
[2021-05-17; Tim comments and revises the wording]
The additional constraints added in the previous wording can induce constraint recursion, as noted in the discussion of LWG 3493. The wording below changes them to Mandates: instead to allow this issue to make progress independently of that issue.
The proposed resolution below has been implemented and tested on top of libstdc++.[2021-05-20; Reflector poll]
Set status to Tentatively Ready after five votes in favour during reflector poll.
[2021-06-07 Approved at June 2021 virtual plenary. Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4885.
Edit 22.10.17.3.1 [func.wrap.func.general], class template function
synopsis, as indicated:
namespace std { template<class> class function; // not defined template<class R, class... ArgTypes> { public: using result_type = R; // 22.10.17.3.2 [func.wrap.func.con], construct/copy/destroy function() noexcept; function(nullptr_t) noexcept; function(const function&); function(function&&) noexcept; template<class F> function(F&&); […] }; […] }
Edit 22.10.17.3.2 [func.wrap.func.con] as indicated:
template<class F> function(F&& f);Let
-8- Constraints:FD
bedecay_t<F>
.
(8.1) —
is_same_v<remove_cvref_t<F>, function>
isfalse
, and(8.2) —
FD
is Lvalue-Callable (22.10.17.3.1 [func.wrap.func.general]) for argument typesF
ArgTypes...
and return typeR
.-?- Mandates:
(?.1) —
is_copy_constructible_v<FD>
istrue
, and(?.2) —
is_constructible_v<FD, F>
istrue
.-9- Preconditions:
-10- Postconditions:meets the Cpp17CopyConstructible requirements.
FFD!*this
istrue
if any of the following hold:
(10.1) —
f
is a null function pointer value.(10.2) —
f
is a null member pointer value.(10.3) —
F
is an instanceremove_cvref_t<F>
is a specialization of thefunction
class template, and!f
istrue
.-11- Otherwise,
-12- Throws: Nothing if*this
targetsa copy ofan object of typef
FD
direct-non-list-initialized with.
std::move(f)std::forward<F>(f)is a specialization of
fFDreference_wrapper
or a function pointer type. Otherwise, may throwbad_alloc
or any exception thrown bythe initialization of the target object. -13- Recommended practice: Implementations should avoid the use of dynamically allocated memory for small callable objects, for example, whereF
's copy or move constructorf
isrefers to an object holding only a pointer or reference to an object and a member function pointer.