This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.

### 2781. Contradictory requirements for `std::function` and `std::reference_wrapper`

Section: 20.14.17.3.2 [func.wrap.func.con] Status: C++17 Submitter: Jonathan Wakely Opened: 2016-10-13 Last modified: 2017-07-30

Priority: 0

View other active issues in [func.wrap.func.con].

View all other issues in [func.wrap.func.con].

View all issues with C++17 status.

Discussion:

`template<class F> function(F f)` says that the effects are "`*this` targets a copy of `f`" which seems pretty clear that if `F` is `reference_wrapper<CallableType>` then the target is a `reference_wrapper<CallableType>`.

But the function copy and move constructors say "shall not throw exceptions if `f`'s target is a callable object passed via `reference_wrapper` or a function pointer." From the requirement above it's impossible for the target to be "a callable object passed via `reference_wrapper`" because if the function was constructed with such a type then the target is the `reference_wrapper` not the callable object it wraps.

This matters because it affects the result of `function::target_type()`, and we have implementation divergence. VC++ and libc++ store the `reference_wrapper` as the target, but libstdc++ and Boost.Function (both written by Doug Gregor) unwrap it, so the following fails:

>     #include <functional>
>     #include <cassert>

>     int main()
>     {
>      auto f = []{};
>      std::function<void()> fn(std::ref(f));
>      assert(fn.target<std::reference_wrapper<decltype(f)>>() != nullptr);
>     }

If `std::function` is intended to deviate from `boost::function` this way then the Throws element for the copy and move constructors is misleading, and should be clarified.

[2016-11-12, Issaquah]

Sat AM: Priority 0; move to Ready

Proposed resolution:

This wording is relative to N4606.

1. Modify 20.14.17.3.2 [func.wrap.func.con] p4 and p6 the same way, as shown:

   >     function(const function& f);

   > > -3- Postconditions: `!*this` if `!f`; otherwise, `*this` targets a copy of `f.target()`.

   > > -4- Throws: shall not throw exceptions if `f`'s target is a callable object passed via specialization of `reference_wrapper` or a function pointer. Otherwise, may throw `bad_alloc` or any exception thrown by the copy constructor of the stored callable object. [Note: Implementations are encouraged to avoid the use of dynamically allocated memory for small callable objects, for example, where `f`'s target is an object holding only a pointer or reference to an object and a member function pointer. — end note]

   >     function(function&& f);

   > > -5- Effects: If `!f`, `*this` has no target; otherwise, move constructs the target of `f` into the target of `*this`, leaving `f` in a valid state with an unspecified value.

   > > -6- Throws: shall not throw exceptions if `f`'s target is a callable object passed via specialization of `reference_wrapper` or a function pointer. Otherwise, may throw `bad_alloc` or any exception thrown by the copy or move constructor of the stored callable object. [Note: Implementations are encouraged to avoid the use of dynamically allocated memory for small callable objects, for example, where `f`'s target is an object holding only a pointer or reference to an object and a member function pointer. — end note]