Experimental function etc.

# Experimental `std::function` etc.

## Introduction

This paper provides wording to the effect that it creates independent fundamental-ts types in namespace `std::experimental` for `function`, `promise`, and `packaged_task`.

## Discussion

Currently, the fundamental-ts refers to `std::function` and has applied extensions to that existing C++11 type, which has caused some significant concerns, which are in detailed described in N4041.

As a consequence of discussing this paper ("Guidelines for the contents of Technical Specifications") and performing straw polls within LEWG the following results had been obtained:

> `std::function`, etc. changes in `std::experimental`?

> SF-F-N-A-SA

> 5-8-5-0-1

This proposal attempts to provide wording to realize these effects.

## Proposed resolution

The proposed wording changes refer to N4023.

1. Add a new entry to Table 1 — "C++ library headers" as indicated:

   > [Drafting note: Currently no header file `<experimental/future>` exists, but is needed to isolate the new types `experimental::promise` and `experimental::packaged_task`. — end drafting note]

   > Table 1 — C++ library headers
   > `…`
   > `<experimental/future>`
   > `…`

2. Modify Table 2 — "Significant features in this technical specification" as indicated:

   > [Drafting note: These changes assume that the assigned feature name suffix remains the same. — end drafting note]

   > Table 2 — Significant features in this technical specification
   > Doc. No. | Title | Primary Section | Macro Name Suffix | Value | Header
   > --- | --- | --- | --- | --- | ---
   > `…`
   > N3916 | Type-erased allocator for `std::function` | 2.3 [mods.func.wrap] 4.2 [exp.func.wrap.func] | `function_erased_allocator` | `201402` | `<functional>` `<experimental/functional>`
   > `…`
   > N3916 | Type-erased allocator for `std::promise` | 2.6 [mods.futures.promise] ?.? [exp.futures.promise] | `promise_erased_allocator` | `201402` | `<future>` `<experimental/future>`
   > N3916 | Type-erased allocator for `std::packaged_task` | 2.7 [mods.futures.task] ?.? [exp.futures.task] | `packaged_task_erased_allocator` | `201402` | `<future>` `<experimental/future>`
   > `…`

3. Remove the existing sub-clause 2.3 [mods.func.wrap] in its entirety:

   2.3 Additions to `std::function` [mods.func.wrap]

   > -1- […]

   > […]

   > -22- Effects: Interchanges the targets of `*this` and `other`.

4. Remove the existing sub-clause 2.6 [mods.futures.promise] in its entirety:

   2.6 Additions to `std::promise` [mods.futures.promise]

   > -1- […]

   > -2- and the following paragraph is inserted […]

5. Remove the existing sub-clause 2.7 [mods.futures.task] in its entirety:

   2.7 Additions to `std::packaged_task` [mods.futures.task]

   > -1- […]

   > -2- and the following paragraph is inserted […]

6. Change header `<experimental/functional>` synopsis, 4.1 [header.functional.synop], as indicated:

   > [Drafting note: The following header synopsis fixes the missing `noexcept` specifications of the comparison functions as recently resolved by LWG 2401 yet. We consider this change editorial at this point, because the two different declarations were already in conflict and this change does not have impact on the actual prototype specifications, which will have the same specifiers as in C++14. — end drafting note]

   >     #include <functional>

   >     namespace std {
   >     namespace experimental {
   >     inline namespace fundamentals_v1 {
   >     […]
   >     // 4.2 Class template function:
   >     template<class> class function; // undefined
   >     template<class R, class... ArgTypes> class function<R(ArgTypes...)>;

   >     template<class R, class... ArgTypes>
   >     void swap(function<R(ArgTypes...)>&, function<R(ArgTypes...)>&);

   >     template<class R, class... ArgTypes>
   >     bool operator==(const function<R(ArgTypes...)>&, nullptr_t) noexcept;
   >     template<class R, class... ArgTypes>
   >     bool operator==(nullptr_t, const function<R(ArgTypes...)>&) noexcept;
   >     template<class R, class... ArgTypes>
   >     bool operator!=(const function<R(ArgTypes...)>&, nullptr_t) noexcept;
   >     template<class R, class... ArgTypes>
   >     bool operator!=(nullptr_t, const function<R(ArgTypes...)>&) noexcept;
   >     […]
   >     }
   >     }

   >     template<class R, class... ArgTypes, class Alloc>
   >     struct uses_allocator<experimental::function<R(ArgTypes...)>, Alloc>;

   >     }

7. Between 4.1 [header.functional.synop] and 4.2 [func.searchers] insert the following new sub-clause as indicated:

   4.2 Class template `function` [exp.func.wrap.func]

   > [Drafting note: The following class template synopsis fixes the missing `noexcept` specification of the `nullptr_t` assignment operator as recently resolved by LWG 2401. We consider this change as editorial, because the fundamental-ts specification refers otherwise to a non-existing declaration in C++14. — end drafting note]

   > The specification of all declarations within this sub-clause 4.2 [exp.func.wrap.func] and its sub-clauses are the same as the corresponding declarations, as specified in C++14 §20.9.11.2, unless explicitly specified otherwise. [Note: `std::experimental::function` uses `std::bad_function_call`, there is no additional type `std::experimental::bad_function_call` — end note].

   > >     namespace std {
   > >       namespace experimental {
   > >       inline namespace fundamentals_v1 {

   > >         template<class> class function; // undefined

   > >         template<class R, class... ArgTypes>
   > >         class function<R(ArgTypes...)> {
   > >         public:
   > >           typedef R result_type;
   > >           typedef T1 argument_type;
   > >           typedef T1 first_argument_type;
   > >           typedef T2 second_argument_type;

   > >           typedef erased_type allocator_type;

   > >           function() noexcept;
   > >           function(nullptr_t) noexcept;
   > >           function(const function&);
   > >           function(function&&);
   > >           template<class F> function(F);
   > >           template<class A> function(allocator_arg_t, const A&) noexcept;
   > >           template<class A> function(allocator_arg_t, const A&,
   > >             nullptr_t) noexcept;
   > >           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);

   > >           function& operator=(const function&);
   > >           function& operator=(function&&);
   > >           function& operator=(nullptr_t) noexcept;
   > >           template<class F> function& operator=(F&&);
   > >           template<class F> function& operator=(reference_wrapper<F>);

   > >           ~function();

   > >           void swap(function&);
   > >           template<class F, class A> void assign(F&&, const A&);

   > >           explicit operator bool() const noexcept;

   > >           R operator()(ArgTypes...) const;

   > >           const type_info& target_type() const noexcept;
   > >           template<class T> T* target() noexcept;
   > >           template<class T> const T* target() const noexcept;

   > >           pmr::memory_resource* get_memory_resource();
   > >         };

   > >         template <class R, class... ArgTypes>
   > >         bool operator==(const function<R(ArgTypes...)>&, nullptr_t) noexcept;
   > >         template <class R, class... ArgTypes>
   > >         bool operator==(nullptr_t, const function<R(ArgTypes...)>&) noexcept;

   > >         template <class R, class... ArgTypes>
   > >         bool operator!=(const function<R(ArgTypes...)>&, nullptr_t) noexcept;
   > >         template <class R, class... ArgTypes>
   > >         bool operator!=(nullptr_t, const function<R(ArgTypes...)>&) noexcept;

   > >         template <class R, class... ArgTypes>
   > >         void swap(function<R(ArgTypes...)>&, function<R(ArgTypes...)>&);

   > >       } // namespace fundamentals_v1
   > >       } // namespace experimental

   > >       template <class R, class... ArgTypes, class Alloc>
   > >       struct uses_allocator<experimental::function<R(ArgTypes...)>, Alloc>
   > >         : true_type { };

   > >     } // namespace std

8. Add the following new sub-clause as a children of 4.2 [exp.func.wrap.func] including its first paragraph, that replaces the corresponding specification provided by paragraph 1 of C++14 §20.9.11.2.1. Then add the following changed member specifications:

   4.2.1 `function` construct/copy/destroy [exp.func.wrap.func.con]

   > [Drafting note: The following first paragraph has been slightly editorially improved to (a) make the difference between `std::function` and `std::experimental::function` clearer (which seems necessary due to the "including" wording that can be parsed in two different ways) and (b) to make intended normative wording clearer, that had been put into parenthesis before, by simply removing these parenthesis) — end drafting note]

   > -?- 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 [memory.type.erased.allocator]). 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()`.

   >     function& operator=(const function& f);

   > > -?- Effects: `function(allocator_arg, get_memory_resource(), f).swap(*this);`

   > > -?- Returns: `*this`

   >     function& operator=(function&& f);

   > > -?- Effects: `function(allocator_arg, get_memory_resource(), std::move(f)).swap(*this);`

   > > -?- Returns: `*this`

   > > [Drafting note: The following Effects element has been fixed and syncs the wording "`*this != NULL`" with the C++14 working draft replacing it with "`*this != nullptr`" — end drafting note]

   >     function& operator=(nullptr_t) noexcept;

   > > -?- Effects: If `*this != nullptr`, destroys the target of `this`.

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

   > > -?- Returns: `*this`

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

   > > -?- Effects: `function(allocator_arg, get_memory_resource(), std::forward<F>(f)).swap(*this);`

   > > -?- Returns: `*this`

   >     template<class F> function& operator=(reference_wrapper<F> f);

   > > -?- Effects: `function(allocator_arg, get_memory_resource(), f).swap(*this);`

   > > -?- Returns: `*this`

9. Add the following new sub-clause as a children of 4.2 [exp.func.wrap.func] and add the following changed member specifications:

   4.2.2 `function` modifiers [exp.func.wrap.func.mod]

   >     void swap(function& other);

   > > > [Drafting note: The previous Preconditions element has been replaced by a Requires element, see LWG 2395 — end drafting note]

   > > -?- Requires: `this->get_memory_resource() == other->get_memory_resource()`.

   > > -?- Effects: Interchanges the targets of `*this` and `other`.

10. Following 8 [memory], insert a new Clause [exp.future] and sub-clause [header.exp.future.synop] as indicated:

    Futures [exp.future]

    Header `<experimental/future>` synopsis [header.exp.future.synop]

    > [Drafting note: An additional editorial fix is applied in the declaration of `swap` for `packaged_task` — end drafting note]

    >     #include <future>

    >     namespace std {
    >       namespace experimental {
    >       inline namespace fundamentals_v1 {

    >         template <class R> class promise;
    >         template <class R> class promise<R&>;
    >         template <> class promise<void>;

    >         template <class R>
    >         void swap(promise<R>& x, promise<R>& y) noexcept;

    >         template <class> class packaged_task; // undefined
    >         template <class R, class... ArgTypes>
    >         class packaged_task<R(ArgTypes...)>;

    >         template <class R, class... ArgTypes>
    >         void swap(packaged_task<R(ArgTypes...)>&, packaged_task<R(ArgTypes...)>&) noexcept;

    >       } // namespace fundamentals_v1
    >       } // namespace experimental

    >       template <class R, class Alloc>
    >       struct uses_allocator<experimental::promise<R>, Alloc>;

    >       template <class R, class Alloc>
    >       struct uses_allocator<experimental::packaged_task<R>, Alloc>;

    >     } // namespace std

11. As children of the new Clause [exp.future], insert a new sub-clause [exp.futures.promise] as indicated:

    ?.? Class template `promise` [exp.futures.promise]

    > The specification of all declarations within this sub-clause [exp.futures.promise] and its sub-clauses are the same as the corresponding declarations, as specified in C++14 §30.6.5, unless explicitly specified otherwise. — end note].

    > >     namespace std {
    > >       namespace experimental {
    > >       inline namespace fundamentals_v1 {

    > >         template <class R>
    > >         class promise {
    > >         public:
    > >           typedef erased_type allocator_type;

    > >           promise();
    > >           template <class Allocator>
    > >           promise(allocator_arg_t, const Allocator& a);
    > >           promise(promise&& rhs) noexcept;
    > >           promise(const promise& rhs) = delete;
    > >           ~promise();

    > >           promise& operator=(promise&& rhs) noexcept;
    > >           promise& operator=(const promise& rhs) = delete;
    > >           void swap(promise& other) noexcept;

    > >           future<R> get_future();

    > >           void set_value(see below);
    > >           void set_exception(exception_ptr p);

    > >           void set_value_at_thread_exit(const R& r);
    > >           void set_value_at_thread_exit(see below);
    > >           void set_exception_at_thread_exit(exception_ptr p);

    > >           pmr::memory_resource* get_memory_resource();
    > >         };

    > >         template <class R>
    > >         void swap(promise<R>& x, promise<R>& y) noexcept;

    > >       } // namespace fundamentals_v1
    > >       } // namespace experimental

    > >       template <class R, class Alloc>
    > >       struct uses_allocator<experimental::promise<R>, Alloc>;

    > >     } // namespace std

    > > > When a `promise` 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).

12. As children of the new Clause [exp.future], insert a new sub-clause [exp.futures.task] as indicated:

    ?.? Class template `packaged_task` [exp.futures.task]

    > The specification of all declarations within this sub-clause [exp.futures.task] and its sub-clauses are the same as the corresponding declarations, as specified in C++14 §30.6.9, unless explicitly specified otherwise. — end note].

    > > [Drafting note: Contrary to C++14 the repeated declaration of the primary `packaged_task` seems unnecessary here, because the same thing is already said in the header synopsis — end drafting note]

    > >     namespace std {
    > >       namespace experimental {
    > >       inline namespace fundamentals_v1 {

    > >         template <class R, class... ArgTypes>
    > >         class packaged_task<R(ArgTypes...)> {
    > >         public:
    > >           typedef erased_type allocator_type;

    > >           packaged_task() noexcept;
    > >           template <class F>
    > >           explicit packaged_task(F&& f);
    > >           template <class F, class Allocator>
    > >           explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f);
    > >           ~packaged_task();

    > >           packaged_task(const packaged_task&) = delete;
    > >           packaged_task& operator=(const packaged_task&) = delete;

    > >           packaged_task(packaged_task&& rhs) noexcept;
    > >           packaged_task& operator=(packaged_task&& rhs) noexcept;
    > >           void swap(packaged_task& other) noexcept;

    > >           bool valid() const noexcept;

    > >           future<R> get_future();

    > >           void operator()(ArgTypes... );
    > >           void make_ready_at_thread_exit(ArgTypes...);

    > >           void reset();

    > >           pmr::memory_resource* get_memory_resource();
    > >         };

    > >         template <class R, class... ArgTypes>
    > >         void swap(packaged_task<R(ArgTypes...)>&, packaged_task<R(ArgTypes...)>&) noexcept;

    > >       } // namespace fundamentals_v1
    > >       } // namespace experimental

    > >       template <class R, class Alloc>
    > >       struct uses_allocator<experimental::packaged_task<R>, Alloc>;

    > >     } // namespace std

    > > > When a `packaged_task` 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).