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

### 2564. [fund.ts.v2] `std::experimental::function` constructors taking allocator arguments may throw exceptions

Section: 4.2 [fund.ts.v2::func.wrap.func] Status: Resolved Submitter: Tim Song Opened: 2015-12-05 Last modified: 2022-11-22

Priority: 3

View all other issues in [fund.ts.v2::func.wrap.func].

View all issues with Resolved status.

Discussion:

Addresses: fund.ts.v2

[This is essentially LWG 2370, but deals with the fundamentals TS version rather than the one in the standard]

In 4.2 [fund.ts.v2::func.wrap.func] of library fundamentals TS, the constructors

>     template<class A> function(allocator_arg_t, const A&) noexcept;
>     template<class A> function(allocator_arg_t, const A&, nullptr_t) noexcept;

must type-erase and store the provided allocator, since the `operator=` specification requires using the "allocator specified in the construction of" the `std::experimental::function` object. This may require a dynamic allocation and so cannot be noexcept. Similarly, the following constructors

>     template<class A> function(allocator_arg_t, const A&, const function&);
>     template<class A> function(allocator_arg_t, const A&, function&&);
>     template<class F, class A> function(allocator_arg_t, const A&, F);

cannot satisfy the C++14 requirement that they "shall not throw exceptions if [the `function` object to be stored] is a callable object passed via `reference_wrapper` or a function pointer" if they need to type-erase and store the allocator.

[2016-11-08, Issaquah]

Not adopted during NB comment resolution

[2022-10-12 LWG telecon]

Set status to "Open". This would be resolved by P0987R2.

[2022-11-22 Resolved by P0897R2 accepted in Kona. Status changed: Open → Resolved.]

Proposed resolution:

This wording is relative to N4562.

1. Edit 4.2 [fund.ts.v2::func.wrap.func], class template `function` synopsis, as follows:

   >     namespace std {
   >       namespace experimental {
   >       inline namespace fundamentals_v2 {

   >         […]

   >         template<class R, class... ArgTypes>
   >         class function<R(ArgTypes...)> {
   >         public:
   >           […]
   >           template<class A> function(allocator_arg_t, const A&) noexcept;
   >           template<class A> function(allocator_arg_t, const A&,
   >             nullptr_t) noexcept;
   >           […]
   >         };

   >         […]

   >       } // namespace fundamentals_v2
   >       } // namespace experimental

   >       […]

   >     } // namespace std

2. Insert the following paragraphs after 4.2.1 [fund.ts.v2::func.wrap.func.con]/1:

   > [Drafting note: This just reproduces the wording from C++14 with the "shall not throw exceptions for `reference_wrapper`/function pointer" provision deleted. — end drafting note]

   > -1- When a `function` constructor that takes a first argument of type `allocator_arg_t` is invoked, the second argument is treated as a type-erased allocator (8.3). If the constructor moves or makes a copy of a function object (C++14 §20.9), including an instance of the `experimental::function` class template, then that move or copy is performed by using-allocator construction with allocator `get_memory_resource()`.

   > >     template <class A> function(allocator_arg_t, const A& a);
   > >     template <class A> function(allocator_arg_t, const A& a, nullptr_t);

   > > > -?- Postconditions: `!*this`.

   > >     template <class A> function(allocator_arg_t, const A& a, const function& f);

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

   > > > -?- Throws: 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]

   > >     template <class A> function(allocator_arg_t, const A& a, function&& f);

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

   > >     template <class F, class A> function(allocator_arg_t, const A& a, F f);

   > > > -?- Requires: `F` shall be `CopyConstructible`.

   > > > -?- Remarks: This constructor shall not participate in overload resolution unless `f` is Callable (C++14 §20.9.11.2) for argument types `ArgTypes...` and return type `R`.

   > > > -?- Postconditions: `!*this` if any of the following hold:

   > > > - `f` is a null function pointer value.

   > > > - `f` is a null member pointer value.

   > > > - `F` is an instance of the `function` class template, and `!f`.

   > > > -?- Otherwise, `*this` targets a copy of `f` initialized with `std::move(f)`. [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]

   > > > -?- Throws: May throw `bad_alloc` or any exception thrown by `F`'s copy or move constructor.

   > -2- In the following descriptions, let `ALLOCATOR_OF(f)` be the allocator specified in the construction of `function f`, or `allocator<char>()` if no allocator was specified.

   > […]