Title
std::function construction vs assignment
Status
c++23
Section
[func.wrap.func.con]
Submitter
Barry Revzin

Created on 2016-09-14.00:00:00 last changed 12 months ago

Messages

Date: 2021-06-07.16:58:04

Proposed resolution:

This wording is relative to N4885.

  1. Edit [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;
    
        // [func.wrap.func.con], construct/copy/destroy
        function() noexcept;
        function(nullptr_t) noexcept;
        function(const function&);
        function(function&&) noexcept;
        template<class F> function(F&&);
    
        […]
      };
    
      […]
    }
    
  2. Edit [func.wrap.func.con] as indicated:

    template<class F> function(F&& f);
    

    Let FD be decay_t<F>.

    -8- Constraints:
    1. (8.1) — is_same_v<remove_cvref_t<F>, function> is false, and

    2. (8.2) — FDF is Lvalue-Callable ([func.wrap.func.general]) for argument types ArgTypes... and return type R.

    -?- Mandates:

    1. (?.1) — is_copy_constructible_v<FD> is true, and

    2. (?.2) — is_constructible_v<FD, F> is true.

    -9- Preconditions: FFD meets the Cpp17CopyConstructible requirements.

    -10- Postconditions: !*this is true if any of the following hold:

    1. (10.1) — f is a null function pointer value.

    2. (10.2) — f is a null member pointer value.

    3. (10.3) — F is an instanceremove_cvref_t<F> is a specialization of the function class template, and !f is true.

    -11- Otherwise, *this targets a copy of fan object of type FD direct-non-list-initialized with std::move(f)std::forward<F>(f).

    -12- Throws: Nothing if fFD is a specialization of reference_wrapper or a function pointer type. Otherwise, may throw bad_alloc or any exception thrown by F's copy or move constructorthe initialization of the target object.

    -13- Recommended practice: Implementations should avoid the use of dynamically allocated memory for small callable objects, for example, where f isrefers to an object holding only a pointer or reference to an object and a member function pointer.

Date: 2021-06-07.00:00:00

[ 2021-06-07 Approved at June 2021 virtual plenary. Status changed: Voting → WP. ]

Date: 2021-05-15.00:00:00

[ 2021-05-20; Reflector poll ]

Set status to Tentatively Ready after five votes in favour during reflector poll.

Date: 2021-05-15.00:00:00

[ 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++.

Date: 2020-11-15.00:00:00

[ 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.

  1. Edit [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;
    
        // [func.wrap.func.con], construct/copy/destroy
        function() noexcept;
        function(nullptr_t) noexcept;
        function(const function&);
        function(function&&) noexcept;
        template<class F> function(F&&);
    
        […]
      };
    
      […]
    }
    
  2. Edit [func.wrap.func.con] as indicated:

    template<class F> function(F&& f);
    

    Let FD be decay_t<F>.

    -8- Constraints:
    1. (8.1) — is_same_v<remove_cvref_t<F>, function> is false,

    2. (8.2) — FDF is Lvalue-Callable ([func.wrap.func.general]) for argument types ArgTypes... and return type R,

    3. (8.3) — is_copy_constructible_v<FD> is true, and

    4. (8.4) — is_constructible_v<FD, F> is true.

    -9- Preconditions: FFD meets the Cpp17CopyConstructible requirements.

    -10- Postconditions: !*this if any of the following hold:

    1. (10.1) — f is a null function pointer value.

    2. (10.2) — f is a null member pointer value.

    3. (10.3) — F is an instanceremove_cvref_t<F> is a specialization of the function class template, and !f is true.

    -11- Otherwise, *this targets a copy of fan object of type FD direct-non-list-initialized with std::move(f)std::forward<F>(f).

    -12- Throws: Nothing if fFD is a specialization of reference_wrapper or a function pointer type. Otherwise, may throw bad_alloc or any exception thrown by F's copy or move constructorthe initialization of the target object.

    -13- Recommended practice: Implementations should avoid the use of dynamically allocated memory for small callable objects, for example, where f isrefers to an object holding only a pointer or reference to an object and a member function pointer.

Date: 2019-07-26.00:00:00

[ 2019-07-26 Tim provides PR. ]

Previous resolution [SUPERSEDED]:

This wording is relative to N4820.

  1. Edit [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;
    
        // [func.wrap.func.con], construct/copy/destroy
        function() noexcept;
        function(nullptr_t) noexcept;
        function(const function&);
        function(function&&) noexcept;
        template<class F> function(F&&);
    
        […]
      };
    
      […]
    }
    
  2. Edit [func.wrap.func.con] p7-11 as indicated:

    template<class F> function(F&& f);
    

    -7- Requires: F shall be Cpp17CopyConstructibleLet FD be decay_t<F>.

    -8- Remarks: This constructor template shall not participate in overload resolution unless F Constraints:

    1. (8.1) — is_same_v<FD, function> is false; and

    2. (8.2) — FD is Lvalue-Callable ([func.wrap.func]) for argument types ArgTypes... and return type R.

    -?- Expects: FD meets the Cpp17CopyConstructible requirements.

    -9- Ensures: !*this if any of the following hold:

    1. (9.1) — f is a null function pointer value.

    2. (9.2) — f is a null member pointer value.

    3. (9.3) — F is an instance remove_cvref_t<F> is a specialization of the function class template, and !f is true.

    -10- Otherwise, *this targets a copy of fan object of type FD direct-non-list-initialized with std::move(f) std::forward<F>(f). [Note: Implementations should avoid the use of dynamically allocated memory for small callable objects, for example, where f is refers to an object holding only a pointer or reference to an object and a member function pointer. — end note]

    -11- Throws: Shall Does not throw exceptions when f FD is a function pointer type or a specialization of reference_wrapper<T> for some T. Otherwise, may throw bad_alloc or any exception thrown by F’s copy or move constructor the initialization of the target object.

Date: 2016-10-08.04:58:13

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.

Is there any reason to favor a by-value constructor over a forwarding-reference constructor?

History
Date User Action Args
2023-11-22 15:47:43adminsetstatus: wp -> c++23
2021-06-07 16:58:04adminsetmessages: + msg11881
2021-06-07 16:58:04adminsetstatus: voting -> wp
2021-05-26 21:11:22adminsetstatus: ready -> voting
2021-05-20 08:53:38adminsetmessages: + msg11826
2021-05-20 08:53:38adminsetstatus: new -> ready
2021-05-18 01:56:01adminsetmessages: + msg11808
2020-11-01 18:00:25adminsetmessages: + msg11526
2019-07-26 13:42:16adminsetmessages: + msg10514
2016-10-03 15:43:16adminsetmessages: + msg8528
2016-09-14 00:00:00admincreate