| Document Number: | |
|---|---|
| Date: | |
| Revises: | |
| Editor: | Google DeepMind | 
Note: this is an early draft. It’s known to be incomplet and incorrekt, and it has lots of bad formatting.
This technical specification describes extensions to the C++
    Standard Library (
This technical specification is non-normative. Some of the library components in this technical specification may be considered for standardization in a future version of C++, but they are not currently part of any C++ standard. Some of the components in this technical specification may never be standardized, and others may be standardized in a substantially changed form.
The goal of this technical specification is to build more widespread existing practice for an expanded C++ standard library. It gives advice on extensions to those vendors who wish to provide them.
The following referenced document is indispensable for the application of this document. For dated references, only the edition cited applies. For undated references, the latest edition of the referenced document (including any amendments) applies.
ISO/IEC 14882:2017 is herein called the C++ Standard. References to clauses within the C++ Standard are written as "C++17 §3.2". The library described in ISO/IEC 14882:2017 clauses 20–33 is herein called the C++ Standard Library.
Unless otherwise specified, the whole of the C++ Standard's Library
    introduction (
Since the extensions described in this technical specification
    are experimental and not part of the C++ standard library, they
    should not be declared directly within namespace
    std.
    Unless otherwise specified, all components described in this technical specification either:
    
::experimental::fundamentals_v3
        to a namespace defined in the C++ Standard Library,
        such as std or std::chrono, or
      std.
      std::experimental::fundamentals_v3::pmr
      because the C++ Standard Library defines std::pmr.
    
    — end example ]
  Each header described in this technical
    specification shall import the contents of
    std::experimental::fundamentals_v3 into
    std::experimental as if by
namespace std::experimental {
  inline namespace fundamentals_v3 {}
}
      This technical specification also describes some experimental modifications to existing interfaces in the C++ Standard Library.
      These modifications are described by quoting the affected parts of the standard
      and using underlining to represent added text and strike-through to represent deleted text.
    
Unless otherwise specified, references to other entities
    described in this technical specification are assumed to be
    qualified with std::experimental::fundamentals_v3::,
    and references to entities described in the standard are assumed
    to be qualified with std::.
Extensions that are expected to eventually be added to an
    existing header <meow> are provided inside the
    <experimental/meow> header, which shall include
    the standard contents of <meow> as if by
#include <meow>New headers are also provided in the
    <experimental/> directory, but without such an
    #include.
| 
 | 
 | 
 | 
This section describes tentative plans for future versions of this technical specification and plans for moving content into future versions of the C++ Standard.
The C++ committee intends to release a new version of this
    technical specification approximately every year, containing the
    library extensions we hope to add to a near-future version of the
    C++ Standard. Future versions will define their contents in
    std::experimental::fundamentals_v4,
    std::experimental::fundamentals_v5, etc., with the
    most recent implemented version inlined into
    std::experimental.
When an extension defined in this or a future version of this
    technical specification represents enough existing practice, it
    will be moved into the next version of the C++ Standard by
    removing the experimental::fundamentals_vN
    segment of its namespace and by removing the
    experimental/ prefix from its header's path.
      For the sake of improved portability between partial implementations of various C++ standards,
      WG21 (the ISO technical committee for the C++ programming language) recommends
      that implementers and programmers follow the guidelines in this section concerning feature-test macros.
      
      Implementers who provide a new standard feature should define a macro with the recommended name,
      in the same circumstances under which the feature is available (for example, taking into account relevant command-line options),
      to indicate the presence of support for that feature.
      Implementers should define that macro with the value specified in
      the most recent version of this technical specification that they have implemented.
      The recommended macro name is "__cpp_lib_experimental_" followed by the string in the "Macro Name Suffix" column.
    
      Programmers who wish to determine whether a feature is available in an implementation should base that determination on
      the presence of the header (determined with __has_include(<header/name>)) and
      the state of the macro with the recommended name.
      (The absence of a tested feature may result in a program with decreased functionality, or the relevant functionality may be provided in a different way.
      A program that strictly depends on support for a feature can just try to use the feature unconditionally;
      presumably, on an implementation lacking necessary support, translation will fail.)
    
| Doc. No. | Title | Primary Section | Macro Name Suffix | Value | Header | 
|---|---|---|---|---|---|
| N4388 | A Proposal to Add a Const-Propagating Wrapper to the Standard Library | propagate_const | 201505 | <experimental/propagate_const> | |
| N3866 | Invocation type traits | invocation_type | 201406 | <experimental/type_traits> | |
| N4502 | The C++ Detection Idiom | detect | 201505 | <experimental/type_traits> | |
| N3916 | Type-erased allocator for std::function | function_erased_allocator | 201406 | <experimental/functional> | |
| N4282 | The World’s Dumbest Smart Pointer | observer_ptr | 201411 | <experimental/memory> | |
| N4273 | Uniform Container Erasure | erase_if | 201411 | <experimental/vector>,<experimental/deque>,<experimental/forward_list>,<experimental/list>,<experimental/map>,<experimental/set>,<experimental/unordered_map>,<experimental/unordered_set> | |
| N4391 | make_array | make_array | 201505 | <experimental/array> | |
| N4257 | Delimited iterators | ostream_joiner | 201411 | <experimental/iterator> | |
| N3916 | Type-erased allocator for std::promise | promise_erased_allocator | 201406 | <experimental/future> | |
| N3916 | Type-erased allocator for std::packaged_task | packaged_task_erased_allocator | 201406 | <experimental/future> | |
| N3925 | A sampleProposal | sample | 201402 | <experimental/algorithm> | |
| N4531 | std::randreplacement | randint | 201511 | <experimental/random> | |
| N4519 | Source-Code Information Capture | source_location | 201505 | <experimental/source_location> | 
Implementations that conform to this technical specification shall behave as if the modifications contained in this section are made to the C++ Standard.
      The following changes to the uses_allocator trait and to the description of uses-allocator construction
      allow a memory_resource pointer act as an allocator in many circumstances.
      
20.7.7 uses_allocator [allocator.uses]
20.7.7.1 uses_allocator trait [allocator.uses.trait]
template <class T, class Alloc> struct uses_allocator; 
- Remarks:
- Automatically detects whether
Thas a nestedallocator_typethat is convertible fromAlloc. Meets the BinaryTypeTrait requirements (C++17 §23.15.1 ). The implementation shall provide a definition that is derived fromtrue_typeif a typeT::allocator_typeexists and eitheris_convertible_v<Alloc, T::allocator_type> != falseorT::allocator_typeis an alias forstd::experimental::erased_type(3.1.2 ), otherwise it shall be derived fromfalse_type. A program may specialize this template to derive fromtrue_typefor a user-defined typeTthat does not have a nestedallocator_typebut nonetheless can be constructed with an allocator where either:
- the first argument of a constructor has type
allocator_arg_tand the second argument has typeAllocor- the last argument of a constructor has type
Alloc.20.7.7.2 uses-allocator construction [allocator.uses.construction]
Uses-allocator construction with allocator
Allocrefers to the construction of an objectobjof typeT, using constructor argumentsv1, v2, ..., vNof typesV1, V2, ..., VN, respectively, and an allocatorallocof typeAlloc, whereAlloceither (1) meets the requirements of an allocator (C++17 §20.5.3.5 ), or (2) is a pointer type convertible tostd::experimental::pmr::memory_resource*(), according to the following rules: 
<experimental/utility> synopsis#include <utility>
namespace std::experimental {
inline namespace fundamentals_v3 {
  // 3.1.2, Class erased_type 
  struct erased_type { };
} // namespace fundamentals_v3
} // namespace std::experimentalerased_typestruct erased_type { }; 
          The erased_type struct is an empty struct that serves as a placeholder for a type T in situations where the actual type T is determined at runtime.
          For example, the nested type, allocator_type, is an alias for erased_type in classes that use type-erased allocators (see 
<experimental/propagate_const> synopsisnamespace std {
  namespace experimental {
  inline namespace fundamentals_v3 {
    // 3.2.2.1, Class template propagate_const overview 
    template <class T> class propagate_const;
    // 3.2.2.8, propagate_const relational operators 
    template <class T>
      constexpr bool operator==(const propagate_const<T>& pt, nullptr_t);
    template <class T>
      constexpr bool operator==(nullptr_t, const propagate_const<T>& pu);
    template <class T>
      constexpr bool operator!=(const propagate_const<T>& pt, nullptr_t);
    template <class T>
      constexpr bool operator!=(nullptr_t, const propagate_const<T>& pu);
    template <class T, class U>
      constexpr bool operator==(const propagate_const<T>& pt, const propagate_const<U>& pu);
    template <class T, class U>
      constexpr bool operator!=(const propagate_const<T>& pt, const propagate_const<U>& pu);
    template <class T, class U>
      constexpr bool operator<(const propagate_const<T>& pt, const propagate_const<U>& pu);
    template <class T, class U>
      constexpr bool operator>(const propagate_const<T>& pt, const propagate_const<U>& pu);
    template <class T, class U>
      constexpr bool operator<=(const propagate_const<T>& pt, const propagate_const<U>& pu);
    template <class T, class U>
      constexpr bool operator>=(const propagate_const<T>& pt, const propagate_const<U>& pu);
    template <class T, class U>
      constexpr bool operator==(const propagate_const<T>& pt, const U& u);
    template <class T, class U>
      constexpr bool operator!=(const propagate_const<T>& pt, const U& u);
    template <class T, class U>
      constexpr bool operator<(const propagate_const<T>& pt, const U& u);
    template <class T, class U>
      constexpr bool operator>(const propagate_const<T>& pt, const U& u);
    template <class T, class U>
      constexpr bool operator<=(const propagate_const<T>& pt, const U& u);
    template <class T, class U>
      constexpr bool operator>=(const propagate_const<T>& pt, const U& u);
    template <class T, class U>
      constexpr bool operator==(const T& t, const propagate_const<U>& pu);
    template <class T, class U>
      constexpr bool operator!=(const T& t, const propagate_const<U>& pu);
    template <class T, class U>
      constexpr bool operator<(const T& t, const propagate_const<U>& pu);
    template <class T, class U>
      constexpr bool operator>(const T& t, const propagate_const<U>& pu);
    template <class T, class U>
      constexpr bool operator<=(const T& t, const propagate_const<U>& pu);
    template <class T, class U>
      constexpr bool operator>=(const T& t, const propagate_const<U>& pu);
    // 3.2.2.9, propagate_const specialized algorithms 
    template <class T>
      constexpr void swap(propagate_const<T>& pt, propagate_const<T>& pt2) noexcept(see below);
    // 3.2.2.10, propagate_const underlying pointer access 
    template <class T>
      constexpr const T& get_underlying(const propagate_const<T>& pt) noexcept;
    template <class T>
      constexpr T& get_underlying(propagate_const<T>& pt) noexcept;
  } // inline namespace fundamentals_v3
  } // namespace experimental
  // 3.2.2.11, propagate_const hash support 
  template <class T> struct hash;
  template <class T>
    struct hash<experimental::fundamentals_v3::propagate_const<T>>;
  // 3.2.2.12, propagate_const comparison function objects 
  template <class T> struct equal_to;
  template <class T>
    struct equal_to<experimental::fundamentals_v3::propagate_const<T>>;
  template <class T> struct not_equal_to;
  template <class T>
    struct not_equal_to<experimental::fundamentals_v3::propagate_const<T>>;
  template <class T> struct less;
  template <class T>
    struct less<experimental::fundamentals_v3::propagate_const<T>>;
  template <class T> struct greater;
  template <class T>
    struct greater<experimental::fundamentals_v3::propagate_const<T>>;
  template <class T> struct less_equal;
  template <class T>
    struct less_equal<experimental::fundamentals_v3::propagate_const<T>>;
  template <class T> struct greater_equal;
  template <class T>
    struct greater_equal<experimental::fundamentals_v3::propagate_const<T>>;
} // namespace stdpropagate_constpropagate_const overviewnamespace std::experimental {
inline namespace fundamentals_v3 {
  template <class T> class propagate_const {
  public:
    using element_type = remove_reference_t<decltype(*declval<T&>())>;
    // 3.2.2.3, propagate_const constructors 
    constexpr propagate_const() = default;
    propagate_const(const propagate_const& p) = delete;
    constexpr propagate_const(propagate_const&& p) = default;
    template <class U>
      see below constexpr propagate_const(propagate_const<U>&& pu);
    template <class U>
      see below constexpr propagate_const(U&& u);
    // 3.2.2.4, propagate_const assignment 
    propagate_const& operator=(const propagate_const& p) = delete;
    constexpr propagate_const& operator=(propagate_const&& p) = default;
    template <class U>
      constexpr propagate_const& operator=(propagate_const<U>&& pu);
    template <class U>
      constexpr propagate_const& operator=(U&& u);
    // 3.2.2.5, propagate_const const observers 
    explicit constexpr operator bool() const;
    constexpr const element_type* operator->() const;
    constexpr operator const element_type*() const; // Not always defined
    constexpr const element_type& operator*() const;
    constexpr const element_type* get() const;
    // 3.2.2.6, propagate_const non-const observers 
    constexpr element_type* operator->();
    constexpr operator element_type*(); // Not always defined
    constexpr element_type& operator*();
    constexpr element_type* get();
    // 3.2.2.7, propagate_const modifiers 
    constexpr void swap(propagate_const& pt) noexcept(see below);
  private:
    T t_; //exposition only
  };
} // inline namespace fundamentals_v3
} // namespace std::experimental
          propagate_const is a wrapper around a pointer-like object type T
          which treats the wrapped pointer as a pointer to const when
          the wrapper is accessed through a const access path.
        
propagate_const requirements on T
          T shall be an object pointer type or a class type for which
          decltype(*declval<T&>()) is an lvalue reference; otherwise
          the program is ill-formed.
        
          If T is an array type, reference type, pointer to function type or
          pointer to (possibly cv-qualified) void, then the program is
          ill-formed.
        
          propagate_const<const int*> is well-formed
    — end note ]
  
propagate_const requirements on class type T
            If T is class
            type then it shall satisfy the following requirements. In this sub-clause
            t denotes a non-const lvalue of type T, ct
            is a const T& bound to t,  element_type denotes
            an object type.
          
            T and const T shall be contextually convertible to bool.
          
If T is implicitly convertible to element_type*,
            (element_type*)t == t.get() shall be true.
          
            If const T is implicitly convertible to const element_type*,
            (const element_type*)ct == ct.get() shall be true.
          
| Expression | Return type | Pre-conditions | Operational semantics | 
|---|---|---|---|
| t.get() | element_type* | ||
| ct.get() | const element_type*orelement_type* |  | t.get() == ct.get(). | 
| *t | element_type& | t.get() != nullptr | *trefers to the same object as*(t.get()) | 
| *ct | const element_type&orelement_type& | ct.get() != nullptr | *ctrefers to the same object as*(ct.get()) | 
| t.operator->() | element_type* | t.get() != nullptr | t.operator->() == t.get() | 
| ct.operator->() | const element_type*orelement_type* | ct.get() != nullptr | ct.operator->() == ct.get() | 
| (bool)t | bool |  | (bool)tis equivalent tot.get() != nullptr | 
| (bool)ct | bool |  | (bool)ctis equivalent toct.get() != nullptr | 
propagate_const constructors
          explicit.  This is typically implemented by declaring two such
            constructors, of which at most one  participates in overload resolution.
    — end note ]
  
template <class U>
see below constexpr propagate_const(propagate_const<U>&& pu); is_constructible_v<T, U&&>.
            The constructor is specified as explicit if and only if
            !is_convertible_v<U&&, T>.
          t_ as if
            direct-non-list-initializing an object of type T with the
            expression std::move(pu.t_).
          template <class U>
see below constexpr propagate_const(U&& u); is_constructible_v<T, U&&>
            and decay_t<U> is not a specialization of propagate_const.
            The constructor is specified as explicit if and only if
            !is_convertible_v<U&&, T>.
          t_ as if
            direct-non-list-initializing an object of type T with
            the expression std::forward<U>(u).
          propagate_const assignmenttemplate <class U>
constexpr propagate_const& operator=(propagate_const<U>&& pu); U is implicitly convertible to T.
          t_ = std::move(pu.t_).*this.template <class U>
constexpr propagate_const& operator=(U&& u); U is implicitly convertible to T and
            decay_t<U> is not a specialization of propagate_const.
          t_ = std::forward<U>(u).*this.propagate_const const observersexplicit constexpr operator bool() const; (bool)t_.constexpr const element_type* operator->() const; get() != nullptr.get().constexpr operator const element_type*() const; get().T is an object pointer type or
            has an implicit conversion to const element_type*.
          constexpr const element_type& operator*() const; get() != nullptr.*get().constexpr const element_type* get() const; t_ if T is an object pointer type,
            otherwise t_.get().
          propagate_const non-const observersconstexpr element_type* operator->(); get() != nullptr.get().constexpr operator element_type*(); get().T is an object pointer type or
          has an implicit conversion to element_type*.
        constexpr element_type& operator*(); get() != nullptr.*get().constexpr element_type* get(); t_ if T is an object pointer type,
          otherwise t_.get().
        propagate_const modifiersconstexpr void swap(propagate_const& pt) noexcept(see below); 
          The constant-expression in the exception-specification is noexcept(swap(t_, pt.t_)).
        
swap(t_, pt.t_).propagate_const relational operatorstemplate <class T>
constexpr bool operator==(const propagate_const<T>& pt, nullptr_t); pt.t_ == nullptr.template <class T>
constexpr bool operator==(nullptr_t, const propagate_const<T>& pt); nullptr == pt.t_.template <class T>
constexpr bool operator!=(const propagate_const<T>& pt, nullptr_t); pt.t_ != nullptr.template <class T>
constexpr bool operator!=(nullptr_t, const propagate_const<T>& pt); nullptr != pt.t_.template <class T, class U>
constexpr bool operator==(const propagate_const<T>& pt, const propagate_const<U>& pu); pt.t_ == pu.t_.template <class T, class U>
constexpr bool operator!=(const propagate_const<T>& pt, const propagate_const<U>& pu); pt.t_ != pu.t_.template <class T, class U>
constexpr bool operator<(const propagate_const<T>& pt, const propagate_const<U>& pu); pt.t_ < pu.t_.template <class T, class U>
constexpr bool operator>(const propagate_const<T>& pt, const propagate_const<U>& pu); pt.t_ > pu.t_.template <class T, class U>
constexpr bool operator<=(const propagate_const<T>& pt, const propagate_const<U>& pu); pt.t_ <= pu.t_.template <class T, class U>
constexpr bool operator>=(const propagate_const<T>& pt, const propagate_const<U>& pu); pt.t_ >= pu.t_.template <class T, class U>
constexpr bool operator==(const propagate_const<T>& pt, const U& u); pt.t_ == u.template <class T, class U>
constexpr bool operator!=(const propagate_const<T>& pt, const U& u); pt.t_ != u.template <class T, class U>
constexpr bool operator<(const propagate_const<T>& pt, const U& u); pt.t_ < u.template <class T, class U>
constexpr bool operator>(const propagate_const<T>& pt, const U& u); pt.t_ > u.template <class T, class U>
constexpr bool operator<=(const propagate_const<T>& pt, const U& u); pt.t_ <= u.template <class T, class U>
constexpr bool operator>=(const propagate_const<T>& pt, const U& u); pt.t_ >= u.template <class T, class U>
constexpr bool operator==(const T& t, const propagate_const<U>& pu); t == pu.t_.template <class T, class U>
constexpr bool operator!=(const T& t, const propagate_const<U>& pu); t != pu.t_.template <class T, class U>
constexpr bool operator<(const T& t, const propagate_const<U>& pu); t < pu.t_.template <class T, class U>
constexpr bool operator>(const T& t, const propagate_const<U>& pu); t > pu.t_.template <class T, class U>
constexpr bool operator<=(const T& t, const propagate_const<U>& pu); t <= pu.t_.template <class T, class U>
constexpr bool operator>=(const T& t, const propagate_const<U>& pu); t >= pu.t_.propagate_const specialized algorithmstemplate <class T>
constexpr void swap(propagate_const<T>& pt1, propagate_const<T>& pt2) noexcept(see below); 
          The constant-expression in the exception-specification is noexcept(pt1.swap(pt2)).
        
pt1.swap(pt2).propagate_const underlying pointer accessAccess to the underlying object pointer type is through free functions rather than member functions. These functions are intended to resemble cast operations to encourage caution when using them.
template <class T>
constexpr const T& get_underlying(const propagate_const<T>& pt) noexcept; template <class T>
constexpr T& get_underlying(propagate_const<T>& pt) noexcept; propagate_const hash supporttemplate <class T>
struct hash<experimental::fundamentals_v3::propagate_const<T>>; 
          For an object p of type propagate_const<T>,
          hash<experimental::fundamentals_v3::propagate_const<T>>()(p)
          shall evaluate to the same value as hash<T>()(p.t_).
        
hash<T> shall be well-formed and well-defined,
          and shall meet the requirements of class template hash.
        propagate_const comparison function objectstemplate <class T>
struct equal_to<experimental::fundamentals_v3::propagate_const<T>>; 
          For objects p, q of type propagate_const<T>,
          equal_to<experimental::fundamentals_v3::propagate_const<T>>()(p,
q)
          shall evaluate to the same value as equal_to<T>()(p.t_,
q.t_).
        
equal_to<T> shall be well-formed and well-defined.
        template <class T>
struct not_equal_to<experimental::fundamentals_v3::propagate_const<T>>; 
          For objects p, q of type propagate_const<T>,
          not_equal_to<experimental::fundamentals_v3::propagate_const<T>>()(p, q)
          shall evaluate to the same value as not_equal_to<T>()(p.t_, q.t_).
        
not_equal_to<T> shall be well-formed and well-defined.
        template <class T>
struct less<experimental::fundamentals_v3::propagate_const<T>>; 
          For objects p, q of type propagate_const<T>,
          less<experimental::fundamentals_v3::propagate_const<T>>()(p,
q)
          shall evaluate to the same value as less<T>()(p.t_,
q.t_).
        
less<T> shall be well-formed and well-defined.
        template <class T>
struct greater<experimental::fundamentals_v3::propagate_const<T>>; 
          For objects p, q of type propagate_const<T>,
          greater<experimental::fundamentals_v3::propagate_const<T>>()(p,
q)
          shall evaluate to the same value as greater<T>()(p.t_,
q.t_).
        
greater<T> shall be well-formed and well-defined.
        template <class T>
struct less_equal<experimental::fundamentals_v3::propagate_const<T>>; 
          For objects p, q of type propagate_const<T>,
          less_equal<experimental::fundamentals_v3::propagate_const<T>>()(p,
q)
          shall evaluate to the same value as less_equal<T>()(p.t_,
q.t_).
        
less_equal<T> shall be well-formed and well-defined.
        template <class T>
struct greater_equal<experimental::fundamentals_v3::propagate_const<T>>; 
          For objects p, q of type propagate_const<T>,
          greater_equal<experimental::fundamentals_v3::propagate_const<T>>()(p,
q)
          shall evaluate to the same value as greater_equal<T>()(p.t_, q.t_).
        
greater_equal<T> shall be well-formed and well-defined.
        #include <type_traits>
namespace std::experimental {
inline namespace fundamentals_v3 {
  // 3.3.2, Other type transformations 
  template <class> class invocation_type; // not defined
  template <class F, class... ArgTypes> class invocation_type<F(ArgTypes...)>;
  template <class> class raw_invocation_type; // not defined
  template <class F, class... ArgTypes> class raw_invocation_type<F(ArgTypes...)>;
  template <class T>
    using invocation_type_t = typename invocation_type<T>::type;
  template <class T>
    using raw_invocation_type_t = typename raw_invocation_type<T>::type;
  // 3.3.3, Detection idiom 
  struct nonesuch;
  template <template<class...> class Op, class... Args>
    using is_detected = see below;
  template <template<class...> class Op, class... Args>
    inline constexpr bool is_detected_v
      = is_detected<Op, Args...>::value;
  template <template<class...> class Op, class... Args>
    using detected_t = see below;
  template <class Default, template<class...> class Op, class... Args>
    using detected_or = see below;
  template <class Default, template<class...> class Op, class... Args>
    using detected_or_t = typename detected_or<Default, Op, Args...>::type;
  template <class Expected, template<class...> class Op, class... Args>
    using is_detected_exact = is_same<Expected, detected_t<Op, Args...>>;
  template <class Expected, template<class...> class Op, class... Args>
    inline constexpr bool is_detected_exact_v
      = is_detected_exact<Expected, Op, Args...>::value;
  template <class To, template<class...> class Op, class... Args>
    using is_detected_convertible = is_convertible<detected_t<Op, Args...>, To>;
  template <class To, template<class...> class Op, class... Args>
    inline constexpr bool is_detected_convertible_v
      = is_detected_convertible<To, Op, Args...>::value;
} // inline namespace fundamentals_v3
} // namespace std::experimentalThis sub-clause contains templates that may be used to transform one type to another following some predefined rule.
        Each of the templates in this subclause shall be a 
        Within this section, define the invocation parameters of INVOKE(f, t1, t2, ..., tN) as follows,
        in which T1 is the possibly cv-qualified type of t1
        and U1 denotes T1& if t1 is an lvalue
        or T1&& if t1 is an rvalue:
      
f is a pointer to a member function of a class T
          the U1 followed by
          the parameters of f matched by t2, ..., tN.
        N == 1 and f is a pointer to member data of a class T
          the U1.
        f is a class object,
          the t1, ..., tN
          of the best viable function (t1, ..., tN
          among the function call operators and surrogate call functions of f.
        f
          matching t1, ... tN.
        
        In all of the above cases,
        if an argument tI matches the ellipsis in the function's tI.
      
S is defined as
        struct S {
  int f(double const &) const;
  void operator()(int, int);
  void operator()(char const *, int i = 2, int j = 3);
  void operator()(...);
};INVOKE(&S::f, S(), 3.5) are (S &&, double const &).INVOKE(S(), 1, 2) are (int, int).INVOKE(S(), "abc", 5) are (const char *, int).
          The defaulted parameter j does not correspond to an argument.INVOKE(S(), locale(), 5) are (locale, int).
          Arguments corresponding to ellipsis maintain their types.| Template | Condition | Comments | 
|---|---|---|
| template <class Fn, class... ArgTypes> | Fnand all types in the parameter packArgTypesshall be complete types, (possibly cv-qualified)void, or arrays of unknown bound. | see below | 
| template <class Fn, class... ArgTypes> | Fnand all types in the parameter packArgTypesshall be complete types, (possibly cv-qualified)void,
            or arrays of unknown bound. | see below | 
        Access checking is performed as if in a context unrelated to Fn and ArgTypes.
        Only the validity of the immediate context of the expression is considered.
        
        The member raw_invocation_type<Fn(ArgTypes...)>::type shall be defined as follows.
        If the expression INVOKE(declval<Fn>(), declval<ArgTypes>()...)
        is ill-formed when treated as an unevaluated operand (type. Otherwise:
      
R denote result_of_t<Fn(ArgTypes...)>.Ti be the INVOKE(declval<Fn>(), declval<ArgTypes>()...) .type shall name the function type R(T1, T2, ...).
        The member invocation_type<Fn(ArgTypes...)>::type shall be defined as follows.
        If raw_invocation_type<Fn(ArgTypes...)>::type does not exist, there shall be no member type.
        Otherwise:
      
A1, A2, … denote ArgTypes...R(T1, T2, …) denote raw_invocation_type_t<Fn(ArgTypes...)>type shall name the function type R(U1, U2, …)
          where Ui is decay_t<Ai> if declval<Ai>() is an rvalue
          otherwise Ti.
        struct nonesuch {
  ~nonesuch() = delete;
  nonesuch(nonesuch const&) = delete;
  void operator=(nonesuch const&) = delete;
};
        nonesuch has no default constructor
        (
template <class Default, class AlwaysVoid,
          template<class...> class Op, class... Args>
struct DETECTOR { // exposition only
  using value_t = false_type;
  using type = Default;
};
template <class Default, template<class...> class Op, class... Args>
struct DETECTOR<Default, void_t<Op<Args...>>, Op, Args...> { // exposition only
  using value_t = true_type;
  using type = Op<Args...>;
};
template <template<class...> class Op, class... Args>
  using is_detected = typename DETECTOR<nonesuch, void, Op, Args...>::value_t;
template <template<class...> class Op, class... Args>
  using detected_t = typename DETECTOR<nonesuch, void, Op, Args...>::type;
template <class Default, template<class...> class Op, class... Args>
  using detected_or = DETECTOR<Default, void, Op, Args...>;// archetypal helper alias for a copy assignment operation:
template <class T>
  using copy_assign_t = decltype(declval<T&>() = declval<T const &>());
// plausible implementation for the is_assignable type trait:
template <class T>
  using is_copy_assignable = is_detected<copy_assign_t, T>;
// plausible implementation for an augmented is_assignable type trait
// that also checks the return type:
template <class T>
  using is_canonical_copy_assignable = is_detected_exact<T&, copy_assign_t, T>;// archetypal helper alias for a particular type member:
template <class T>
  using diff_t = typename T::difference_type;
// alias the type member, if it exists, otherwise alias ptrdiff_t:
template <class Ptr>
  using difference_type = detected_or_t<ptrdiff_t, diff_t, Ptr>;<experimental/functional> synopsis#include <functional>
namespace std {
  namespace experimental {
  inline namespace fundamentals_v3 {
    // 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;
  } // namespace fundamentals_v3
  } // namespace experimental
  template<class R, class... ArgTypes, class Alloc>
  struct uses_allocator<experimental::function<R(ArgTypes...)>, Alloc>;
} // namespace stdfunction
      The specification of all declarations within this sub-clause 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_v3 {
    template<class> class function; // undefined
    template<class R, class... ArgTypes>
    class function<R(ArgTypes...)> {
    public:
      using result_type = R;
      using argument_type = T1;
      using first_argument_type T1;
      using second_argument_type = T2;
      using allocator_type = erased_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&);
      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() const 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>
    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_v3
  } // namespace experimental
  template <class R, class... ArgTypes, class Alloc>
  struct uses_allocator<experimental::function<R(ArgTypes...)>, Alloc>
    : true_type { };
} // namespace stdfunction construct/copy/destroy
        When a function constructor that takes a first argument of type allocator_arg_t is invoked,
        the second argument is treated as a experimental::function class template,
        then that move or copy is performed by get_memory_resource().
      
        In the following descriptions, let ALLOCATOR_OF(f) be the allocator specified in the construction of function f,
        or the value of experimental:: at the time of the construction of f if no allocator was specified.
      
function& operator=(const function& f); function(allocator_arg, ALLOCATOR_OF(*this), f).swap(*this);*this.function& operator=(function&& f); function(allocator_arg, ALLOCATOR_OF(*this), std::move(f)).swap(*this);*this.function& operator=(nullptr_t) noexcept; *this != nullptr, destroys the target of this.!(*this).
        The memory resource returned by get_memory_resource() after the assignment is equivalent to the memory resource before the assignment.
        get_memory_resource() might change
    — end note ]
  *this.template<class F> function& operator=(F&& f); function(allocator_arg, ALLOCATOR_OF(*this), std::forward<F>(f)).swap(*this);*this.declval<decay_t<F>&>() is Callable (ArgTypes... and return type R.template<class F> function& operator=(reference_wrapper<F> f); function(allocator_arg, ALLOCATOR_OF(*this), f).swap(*this);*this.function modifiersvoid swap(function& other); *this->get_memory_resource() == *other.get_memory_resource().*this and other.*this and other are not interchanged.#include <memory>
namespace std {
  namespace experimental {
  inline namespace fundamentals_v3 {
    // 5.2, Non-owning pointers 
    template <class W> class observer_ptr;
    // 5.2.6, observer_ptr specialized algorithms 
    template <class W>
    void swap(observer_ptr<W>&, observer_ptr<W>&) noexcept;
    template <class W>
    observer_ptr<W> make_observer(W*) noexcept;
    // (in)equality operators
    template <class W1, class W2>
    bool operator==(observer_ptr<W1>, observer_ptr<W2>);
    template <class W1, class W2>
    bool operator!=(observer_ptr<W1>, observer_ptr<W2>);
    template <class W>
    bool operator==(observer_ptr<W>, nullptr_t) noexcept;
    template <class W>
    bool operator!=(observer_ptr<W>, nullptr_t) noexcept;
    template <class W>
    bool operator==(nullptr_t, observer_ptr<W>) noexcept;
    template <class W>
    bool operator!=(nullptr_t, observer_ptr<W>) noexcept;
    // ordering operators
    template <class W1, class W2>
    bool operator<(observer_ptr<W1>, observer_ptr<W2>);
    template <class W1, class W2>
    bool operator>(observer_ptr<W1>, observer_ptr<W2>);
    template <class W1, class W2>
    bool operator<=(observer_ptr<W1>, observer_ptr<W2>);
    template <class W1, class W2>
    bool operator>=(observer_ptr<W1>, observer_ptr<W2>);
  } // inline namespace fundamentals_v3
  } // namespace experimental
  // 5.2.7, observer_ptr hash support 
  template <class T> struct hash;
  template <class T> struct hash<experimental::observer_ptr<T>>;
} // namespace std
      A non-owning pointer, known as an observer, is an object o that stores a pointer to a second object, w.
      In this context, w is known as a watched object.
      nullptr.
    — end note ]
  o and w.
    
      Specializations of observer_ptr shall meet the requirements of a CopyConstructible and CopyAssignable type.
      The template parameter W of an observer_ptr shall not be a reference type, but may be an incomplete type.
    
      observer_ptr include clarity of interface specification in new code,
      and interoperability with pointer-based legacy code.
    — end note ]
  
observer_ptr overviewnamespace std::experimental {
inline namespace fundamentals_v3 {
  template <class W> class observer_ptr {
    using pointer = add_pointer_t<W>;            // exposition-only
    using reference = add_lvalue_reference_t<W>; // exposition-only
  public:
    // publish our template parameter and variations thereof
    using element_type = W;
    // 5.2.2, observer_ptr constructors 
    // default c’tor
    constexpr observer_ptr() noexcept;
    // pointer-accepting c’tors
    constexpr observer_ptr(nullptr_t) noexcept;
    constexpr explicit observer_ptr(pointer) noexcept;
    // copying c’tors (in addition to compiler-generated copy c’tor)
    template <class W2> constexpr observer_ptr(observer_ptr<W2>) noexcept;
    // 5.2.3, observer_ptr observers 
    constexpr pointer get() const noexcept;
    constexpr reference operator*() const;
    constexpr pointer operator->() const noexcept;
    constexpr explicit operator bool() const noexcept;
    // 5.2.4, observer_ptr conversions 
    constexpr explicit operator pointer() const noexcept;
    // 5.2.5, observer_ptr modifiers 
    constexpr pointer release() noexcept;
    constexpr void reset(pointer = nullptr) noexcept;
    constexpr void swap(observer_ptr&) noexcept;
  }; // observer_ptr<>
} // inline namespace fundamentals_v3
} // namespace std::experimentalobserver_ptr constructorsconstexpr observer_ptr() noexcept; constexpr observer_ptr(nullptr_t) noexcept; get() == nullptr.constexpr explicit observer_ptr(pointer other) noexcept; get() == other.template <class W2> constexpr observer_ptr(observer_ptr<W2> other) noexcept; get() == other.get().W2* is convertible to W*.observer_ptr observersconstexpr pointer get() const noexcept; constexpr reference operator*() const; get() != nullptr.*get().constexpr pointer operator->() const noexcept; get().constexpr explicit operator bool() const noexcept; get() != nullptr.observer_ptr conversionsconstexpr explicit operator pointer() const noexcept; get().observer_ptr modifiersconstexpr pointer release() noexcept; get() == nullptr.get() had at the start of the call to release.constexpr void reset(pointer p = nullptr) noexcept; get() == p.constexpr void swap(observer_ptr& other) noexcept; swap on the stored pointers of *this and other.observer_ptr specialized algorithmstemplate <class W>
void swap(observer_ptr<W>& p1, observer_ptr<W>& p2) noexcept; p1.swap(p2).template <class W> observer_ptr<W> make_observer(W* p) noexcept; observer_ptr<W>{p}.template <class W1, class W2>
bool operator==(observer_ptr<W1> p1, observer_ptr<W2> p2); p1.get() == p2.get().template <class W1, class W2>
bool operator!=(observer_ptr<W1> p1, observer_ptr<W2> p2); not (p1 == p2).template <class W>
bool operator==(observer_ptr<W> p, nullptr_t) noexcept; template <class W>
bool operator==(nullptr_t, observer_ptr<W> p) noexcept; not p.template <class W>
bool operator!=(observer_ptr<W> p, nullptr_t) noexcept; template <class W>
bool operator!=(nullptr_t, observer_ptr<W> p) noexcept; (bool)p.template <class W1, class W2>
bool operator<(observer_ptr<W1> p1, observer_ptr<W2> p2); less<W3>()(p1.get(), p2.get()),
          where W3 is the composite pointer type (W1* and W2*.
        template <class W1, class W2>
bool operator>(observer_ptr<W1> p1, observer_ptr<W2> p2); p2 < p1.template <class W1, class W2>
bool operator<=(observer_ptr<W1> p1, observer_ptr<W2> p2); not (p2 < p1).template <class W1, class W2>
bool operator>=(observer_ptr<W1> p1, observer_ptr<W2> p2); not (p1 < p2).observer_ptr hash supporttemplate <class T> struct hash<experimental::observer_ptr<T>>; 
          The template specialization shall meet the requirements of class template hash (p of type observer_ptr<T>,
          hash<observer_ptr<T>>()(p) shall evaluate to the same value as hash<T*>()(p.get()).
        
      A type-erased allocator is an allocator or memory resource, alloc,
      used to allocate internal data structures for an object X of type C,
      but where C is not dependent on the type of alloc.
      Once alloc has been supplied to X (typically as a constructor argument),
      alloc can be retrieved from X only as a pointer rptr of static type std::pmr::memory_resource* (rptr is computed from alloc depends on the type of alloc as described in 
| If the type of allocis | then the value of rptris | 
|---|---|
| non-existent — no allocspecified | The value of pmr::get_default_resource()at the time of construction. | 
| nullptr_t | The value of pmr::get_default_resource()at the time of construction. | 
| a pointer type convertible to pmr::memory_resource* | static_cast<pmr::memory_resource*>(alloc) | 
| pmr::polymorphic_allocator<U> | alloc.resource() | 
| any other type meeting the Allocator requirements ( | a pointer to a value of type pmr::resource_adaptor<A>whereAis the type ofalloc.rptrremains valid only for the lifetime ofX. | 
| None of the above | The program is ill-formed. | 
Additionally, class C shall meet the following requirements:
C::allocator_type shall be identical to std::experimental::erased_type.X.get_memory_resource() returns rptr.<experimental/memory_resource> synopsisnamespace std::experimental {
inline namespace fundamentals_v3 {
namespace pmr {
  // The name resource_adaptor_imp is for exposition only.
  template <class Allocator> class resource_adaptor_imp;
  template <class Allocator>
    using resource_adaptor = resource_adaptor_imp<
      typename allocator_traits<Allocator>::template rebind_alloc<char>>;
} // namespace pmr
} // inline namespace fundamentals_v3
} // namespace std::experimentalresource_adaptorresource_adaptor
        An instance of resource_adaptor<Allocator> is an adaptor that wraps a memory_resource interface around Allocator.
        In order that resource_adaptor<X<T>> and resource_adaptor<X<U>> are the same type for any allocator template X and types T and U,
        resource_adaptor<Allocator> is rendered as an alias to a class template such that Allocator is rebound to a char value type in every specialization of the class template.
        The requirements on this class template are defined below.
        The name resource_adaptor_imp is for exposition only and is not normative,
        but the definitions of the members of that class, whatever its name, are normative.
        In addition to the Allocator requirements (resource_adaptor shall meet the following additional requirements:
      
typename allocator_traits<Allocator>::pointer shall be identical to typename allocator_traits<Allocator>::value_type*.typename allocator_traits<Allocator>::const_pointer shall be identical to typename allocator_traits<Allocator>::value_type const*.typename allocator_traits<Allocator>::void_pointer shall be identical to void*.typename allocator_traits<Allocator>::const_void_pointer shall be identical to void const*.
// The name resource_adaptor_imp is for exposition only.
template <class Allocator>
class resource_adaptor_imp : public memory_resource {
  // for exposition only
  Allocator m_alloc;
public:
  using allocator_type = Allocator;
  resource_adaptor_imp() = default;
  resource_adaptor_imp(const resource_adaptor_imp&) = default;
  resource_adaptor_imp(resource_adaptor_imp&&) = default;
  explicit resource_adaptor_imp(const Allocator& a2);
  explicit resource_adaptor_imp(Allocator&& a2);
  resource_adaptor_imp& operator=(const resource_adaptor_imp&) = default;
  allocator_type get_allocator() const { return m_alloc; }
protected:
  virtual void* do_allocate(size_t bytes, size_t alignment);
  virtual void do_deallocate(void* p, size_t bytes, size_t alignment);
  virtual bool do_is_equal(const memory_resource& other) const noexcept;
};
template <class Allocator>
  using resource_adaptor = typename resource_adaptor_imp<
    typename allocator_traits<Allocator>::template rebind_alloc<char>>;resource_adaptor_imp constructorsexplicit resource_adaptor_imp(const Allocator& a2); m_alloc with a2.explicit resource_adaptor_imp(Allocator&& a2); m_alloc with std::move(a2).resource_adaptor_imp member functionsvoid* do_allocate(size_t bytes, size_t alignment); m_alloc.allocate. The size and alignment of the allocated memory shall meet the requirements for a class derived from memory_resource (void do_deallocate(void* p, size_t bytes, size_t alignment); p was previously allocated using A.allocate, where A == m_alloc, and not subsequently deallocated.m_alloc.deallocate().bool do_is_equal(const memory_resource& other) const noexcept; Let p be dynamic_cast<const resource_adaptor_imp*>(&other).
false if p is null, otherwise the value of m_alloc == p->m_alloc.
        For brevity, this section specifies the contents of 9 headers,
        each of which behaves as described by 
namespace std::experimental {
inline namespace fundamentals_v3 {
  // 6.1.2, Function template erase_if 
  // 6.1.3, Function template erase 
  // <experimental/string>
  template <class charT, class traits, class A, class Predicate>
    void erase_if(basic_string<charT, traits, A>& c, Predicate pred);
  template <class charT, class traits, class A, class U>
    void erase(basic_string<charT, traits, A>& c, const U& value);
  // <experimental/deque>
  template <class T, class A, class Predicate>
    void erase_if(deque<T, A>& c, Predicate pred);
  template <class T, class A, class U>
    void erase(deque<T, A>& c, const U& value);
  // <experimental/vector>
  template <class T, class A, class Predicate>
    void erase_if(vector<T, A>& c, Predicate pred);
  template <class T, class A, class U>
    void erase(vector<T, A>& c, const U& value);
  // <experimental/forward_list>
  template <class T, class A, class Predicate>
    void erase_if(forward_list<T, A>& c, Predicate pred);
  template <class T, class A, class U>
    void erase(forward_list<T, A>& c, const U& value);
  // <experimental/list>
  template <class T, class A, class Predicate>
    void erase_if(list<T, A>& c, Predicate pred);
  template <class T, class A, class U>
    void erase(list<T, A>& c, const U& value);
  // <experimental/map>
  template <class K, class T, class C, class A, class Predicate>
    void erase_if(map<K, T, C, A>& c, Predicate pred);
  template <class K, class T, class C, class A, class Predicate>
    void erase_if(multimap<K, T, C, A>& c, Predicate pred);
  // <experimental/set>
  template <class K, class C, class A, class Predicate>
    void erase_if(set<K, C, A>& c, Predicate pred);
  template <class K, class C, class A, class Predicate>
    void erase_if(multiset<K, C, A>& c, Predicate pred);
  // <experimental/unordered_map>
  template <class K, class T, class H, class P, class A, class Predicate>
    void erase_if(unordered_map<K, T, H, P, A>& c, Predicate pred);
  template <class K, class T, class H, class P, class A, class Predicate>
    void erase_if(unordered_multimap<K, T, H, P, A>& c, Predicate pred);
  // <experimental/unordered_set>
  template <class K, class H, class P, class A, class Predicate>
    void erase_if(unordered_set<K, H, P, A>& c, Predicate pred);
  template <class K, class H, class P, class A, class Predicate>
    void erase_if(unordered_multiset<K, H, P, A>& c, Predicate pred);
} // inline namespace fundamentals_v3
} // namespace std::experimentalerase_iftemplate <class charT, class traits, class A, class Predicate>
void erase_if(basic_string<charT, traits, A>& c, Predicate pred); template <class T, class A, class Predicate>
void erase_if(deque<T, A>& c, Predicate pred); template <class T, class A, class Predicate>
void erase_if(vector<T, A>& c, Predicate pred); c.erase(remove_if(c.begin(), c.end(), pred), c.end());template <class T, class A, class Predicate>
void erase_if(forward_list<T, A>& c, Predicate pred); template <class T, class A, class Predicate>
void erase_if(list<T, A>& c, Predicate pred); c.remove_if(pred);template <class K, class T, class C, class A, class Predicate>
void erase_if(map<K, T, C, A>& c, Predicate pred); template <class K, class T, class C, class A, class Predicate>
void erase_if(multimap<K, T, C, A>& c, Predicate pred); template <class K, class C, class A, class Predicate>
void erase_if(set<K, C, A>& c, Predicate pred); template <class K, class C, class A, class Predicate>
void erase_if(multiset<K, C, A>& c, Predicate pred); template <class K, class T, class H, class P, class A, class Predicate>
void erase_if(unordered_map<K, T, H, P, A>& c, Predicate pred); template <class K, class T, class H, class P, class A, class Predicate>
void erase_if(unordered_multimap<K, T, H, P, A>& c, Predicate pred); template <class K, class H, class P, class A, class Predicate>
void erase_if(unordered_set<K, H, P, A>& c, Predicate pred); template <class K, class H, class P, class A, class Predicate>
void erase_if(unordered_multiset<K, H, P, A>& c, Predicate pred); for (auto i = c.begin(), last = c.end(); i != last; ) {
  if (pred(*i)) {
    i = c.erase(i);
  } else {
    ++i;
  }
}template <class charT, class traits, class A, class U>
void erase(basic_string<charT, traits, A>& c, const U& value); template <class T, class A, class U>
void erase(deque<T, A>& c, const U& value); template <class T, class A, class U>
void erase(vector<T, A>& c, const U& value); c.erase(remove(c.begin(), c.end(), value), c.end());template <class T, class A, class U>
void erase(forward_list<T, A>& c, const U& value); template <class T, class A, class U>
void erase(list<T, A>& c, const U& value); erase_if(c, [&](auto& elem) { return elem == value; });erase() for associative containers and unordered associative containers are intentionally not provided.
      
    — end note ]
  array#include <array>
namespace std::experimental {
inline namespace fundamentals_v3 {
  // 6.2.2, Array creation functions 
  template <class D = void, class... Types>
    constexpr array<VT, sizeof...(Types)> make_array(Types&&... t);
  template <class T, size_t N>
    constexpr array<remove_cv_t<T>, N> to_array(T (&a)[N]);
} // inline namespace fundamentals_v3
} // namespace std::experimentaltemplate <class D = void, class... Types>
  constexpr array<VT, sizeof...(Types)> make_array(Types&&... t); 
          Let Ui be decay_t<Ti> for each Ti in Types.
        
D is void and at least one Ui is a specialization of reference_wrapper.
        array<VT, sizeof...(Types)>{ std::forward<Types>(t)... }, where VT is common_type_t<Types...> if D is void, otherwise VT is D.
        int i = 1; int& ri = i;
auto a1 = make_array(i, ri);         // a1 is of type array<int, 2>
auto a2 = make_array(i, ri, 42L);    // a2 is of type array<long, 3>
auto a3 = make_array<long>(i, ri);   // a3 is of type array<long, 2>
auto a4 = make_array<long>();        // a4 is of type array<long, 0>
auto a5 = make_array();              // ill-formedtemplate <class T, size_t N>
constexpr array<remove_cv_t<T>, N> to_array(T (&a)[N]); array<remove_cv_t<T>, N> such that each element is copy-initialized with the corresponding element of a.
        <experimental/iterator> synopsis#include <iterator>
namespace std::experimental {
inline namespace fundamentals_v3 {
  // 7.2, Class template ostream_joiner 
  template <class DelimT, class charT = char, class traits = char_traits<charT> >
      class ostream_joiner;
  template <class charT, class traits, class DelimT>
    ostream_joiner<decay_t<DelimT>, charT, traits>
    make_ostream_joiner(basic_ostream<charT, traits>& os, DelimT&& delimiter);
} // inline namespace fundamentals_v3
} // namespace std::experimentalostream_joiner
      ostream_joiner writes (using operator<<) successive elements onto the output stream from which it was constructed.
      The delimiter that it was constructed with is written to the stream between every two Ts that are written.
      It is not possible to get a value out of the output iterator.
      Its only use is as an output iterator in situations like
    
while (first != last)
  *result++ = *first++;
    ostream_joiner is defined as
  
namespace std::experimental {
inline namespace fundamentals_v3 {
  template <class DelimT, class charT = char, class traits = char_traits<charT> >
  class ostream_joiner {
  public:
    using char_type = charT;
    using traits_type = traits;
    using ostream_type = basic_ostream<charT, traits>;
    using iterator_category = output_iterator_tag;
    using value_type = void;
    using difference_type = void;
    using pointer = void;
    using reference = void;
    ostream_joiner(ostream_type& s, const DelimT& delimiter);
    ostream_joiner(ostream_type& s, DelimT&& delimiter);
    template<typename T>
    ostream_joiner& operator=(const T& value);
    ostream_joiner& operator*() noexcept;
    ostream_joiner& operator++() noexcept;
    ostream_joiner& operator++(int) noexcept;
  private:
    ostream_type* out_stream; // exposition only
    DelimT delim;             // exposition only
    bool first_element;       // exposition only
  };
} // inline namespace fundamentals_v3
} // namespace std::experimentalostream_joiner constructorostream_joiner(ostream_type& s, const DelimT& delimiter); out_stream with std::addressof(s),
          delim with delimiter,
          and first_element with true.
        ostream_joiner(ostream_type& s, DelimT&& delimiter); out_stream with std::addressof(s),
          delim with move(delimiter),
          and first_element with true.
        ostream_joiner operationstemplate<typename T>
ostream_joiner& operator=(const T& value); if (!first_element)
  *out_stream << delim;
first_element = false;
*out_stream << value;
return *this;ostream_joiner& operator*() noexcept; *this.ostream_joiner& operator++() noexcept; ostream_joiner& operator++(int) noexcept; *this.ostream_joiner creation functiontemplate <class charT, class traits, class DelimT>
ostream_joiner<decay_t<DelimT>, charT, traits>
make_ostream_joiner(basic_ostream<charT, traits>& os, DelimT&& delimiter); ostream_joiner<decay_t<DelimT>, charT, traits>(os, forward<DelimT>(delimiter));#include <future>
namespace std {
  namespace experimental {
  inline namespace fundamentals_v3 {
    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_v3
  } // 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 stdpromise
      The specification of all declarations within this sub-clause 
namespace std {
  namespace experimental {
  inline namespace fundamentals_v3 {
    template <class R>
    class promise {
    public:
      using allocator_type = erased_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() const noexcept;
    };
    template <class R>
    void swap(promise<R>& x, promise<R>& y) noexcept;
  } // namespace fundamentals_v3
  } // 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 (
packaged_task
      The specification of all declarations within this sub-clause 
namespace std {
  namespace experimental {
  inline namespace fundamentals_v3 {
    template <class R, class... ArgTypes>
    class packaged_task<R(ArgTypes...)> {
    public:
      using allocator_type = erased_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() const noexcept;
    };
    template <class R, class... ArgTypes>
    void swap(packaged_task<R(ArgTypes...)>&, packaged_task<R(ArgTypes...)>&) noexcept;
  } // namespace fundamentals_v3
  } // 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 (
<experimental/algorithm> synopsis#include <algorithm>
namespace std::experimental {
inline namespace fundamentals_v3 {
  // 9.2, Sampling 
  template<class PopulationIterator, class SampleIterator, class Distance>
  SampleIterator sample(PopulationIterator first, PopulationIterator last,
                        SampleIterator out, Distance n);
  // 9.3, Shuffle 
  template<class RandomAccessIterator>
  void shuffle(RandomAccessIterator first, RandomAccessIterator last);
} // inline namespace fundamentals_v3
} // namespace std::experimentaltemplate<class PopulationIterator, class SampleIterator, class Distance>
SampleIterator sample(PopulationIterator first, PopulationIterator last,
                      SampleIterator out, Distance n); return ::std::sample(first, last, out, n, g);g denotes
        the per-thread engine (g shall serve as the
        implementation’s source of randomness.
      template<class RandomAccessIterator>
  void shuffle(RandomAccessIterator first, RandomAccessIterator last); [first,last)
        such that each possible permutation of those elements has equal
        probability of appearance.RandomAccessIterator shall satisfy the
        requirements of ValueSwappable ((last - first) - 1 swaps.<experimental/random> synopsis#include <random>
namespace std::experimental {
inline namespace fundamentals_v3 {
  // 10.1.2.1, Function template randint 
  template <class IntType>
  IntType randint(IntType a, IntType b);
  void reseed();
  void reseed(default_random_engine::result_type value);
} // inline namespace fundamentals_v3
} // namespace std::experimentalrandintA separate per-thread engine of type default_random_engine
      (
template<class IntType>
IntType randint(IntType a, IntType b); a ≤ b.IntType (a ≤ i ≤ b,
          produced from a thread-local instance of uniform_int_distribution<IntType>
          (void reseed(); void reseed(default_random_engine::result_type value); g be the per-thread engine. The first
          form sets g to an unpredictable state. The second form
          invokes g.seed(value).randint do not
          depend on values produced by g before calling reseed.
          reseed also resets any instances of uniform_int_distribution
          used by randint.
    — end note ]
  <experimental/source_location> synopsisnamespace std::experimental {
inline namespace fundamentals_v3 {
  struct source_location;
} // inline namespace fundamentals_v3
} // namespace std::experimentalsource_locationnamespace std::experimental {
inline namespace fundamentals_v3 {
  struct source_location {
    // 11.2.1, source_location creation 
    static constexpr source_location current() noexcept;
    constexpr source_location() noexcept;
    // 11.2.2, source_location field access 
    constexpr uint_least32_t line() const noexcept;
    constexpr uint_least32_t column() const noexcept;
    constexpr const char* file_name() const noexcept;
    constexpr const char* function_name() const noexcept;
  };
} // inline namespace fundamentals_v3
} // namespace std::experimental
      source_location is to have a small size and efficient copying.
    — end note ]
  
source_location creationstatic constexpr source_location current() noexcept; current,
          returns a source_location with an implementation-defined value.
          The value should be affected by #line
          (__LINE__ and __FILE__.
          If invoked in some other way, the value returned is unspecified.
        current should correspond to the location of
          the constructor or aggregate initialization that initializes the member.
        
          source_location will be the location of the call to current at the call site.
    — end note ]
  
struct s {
  source_location member = source_location::current();
  int other_member;
  s(source_location loc = source_location::current())
    : member(loc) // values of member will be from call-site
  {}
  s(int blather) : // values of member should be hereabouts
    other_member(blather) {}
  s(double) // values of member should be hereabouts
  {}
};
void f(source_location a = source_location::current()) {
  source_location b = source_location::current(); // values in b represent this line
}
void g() {
  f(); // f’s first argument corresponds to this line of code
  source_location c = source_location::current();
  f(c); // f’s first argument gets the same values as c, above
}constexpr source_location() noexcept; source_location.source_location field accessconstexpr uint_least32_t line() const noexcept; constexpr uint_least32_t column() const noexcept; constexpr const char* file_name() const noexcept; constexpr const char* function_name() const noexcept;