Author: C++11 Implementations of Standard Components Added in Later C++ Standards

# Boost.Compat

C++11 Implementations of Standard Components Added in Later C++ Standards

## Overview

Boost.Compat is a repository of C++11 implementations of standard components added in later C++ standards. Its target audience is Boost library authors whose libraries support a lower C++ standard, but wish to utilize a component added in a subsequent one.

The criteria for inclusion in Boost.Compat are as follows:

- The implementation should be relatively simple and header-only.

- The component must implement the standard functionality exactly, without deviations or extensions. This allows (but does not require) the implementation to be a simple `using` declaration in case the standard component is available.

- The component must not depend on any Boost libraries except Boost.Config, Boost.Assert, or Boost.ThrowException.

- The component must not be a vocabulary type, visible in the library APIs. The user should never see a `boost::compat` type; the use of Compat types should be confined to library implementations.

## Revision History

### Changes in 1.90.0

- Added `to_underlying.hpp` (contributed by Braden Ganetsky.)

### Changes in 1.89.0

- Added `move_only_function.hpp`.

### Changes in 1.87.0

- Added `to_array.hpp` (contributed by Ruben Perez Hidalgo.)

### Changes in 1.86.0

- Added `bind_front.hpp`, `bind_back.hpp`, `invoke.hpp`, `mem_fn.hpp`, `integer_sequence.hpp` and `type_traits.hpp`.

- Added `function_ref.hpp`.

### Changes in 1.83.0

- Added `latch.hpp`, an implementation of `std::latch` (contributed by Christian Mazakas.)

- Added `shared_lock.hpp`, a (partial) implementation of `std::shared_lock` (contributed by Christian Mazakas.)

## <boost/compat/bind_back.hpp>

### Description

The header `<boost/compat/bind_back.hpp>` implements the C++20 function `std::bind_back`.

`bind_back` is a limited variant of `std::bind`. It only supports binding the last several parameters of a function object to specific argument values.

### Example

    struct X
    {
        void f(int a, int b) const noexcept;
    };

    int main()
    {
        auto fn = boost::compat::bind_back(&X::f, 1, 2);

        X x;
        fn(x); // calls x.f(1, 2)
    }

### Synopsis

    namespace boost
    {
    namespace compat
    {

    template<class F, class... A> auto bind_back(F&& f, A&&... a);

    } // namespace compat
    } // namespace boost

### bind_back

    template<class F, class... A> auto bind_back( F&& f, A&&... a );

Returns: | A function object `fn` such that `fn(b…​)` is equivalent to `invoke(f, b…​, a…​)`.

## <boost/compat/bind_front.hpp>

### Description

The header `<boost/compat/bind_front.hpp>` implements the C++20 function `std::bind_front`.

`bind_front` is a limited variant of `std::bind`. It only supports binding the first several parameters of a function object to specific argument values.

### Example

    struct X
    {
        void f(int a, int b) const noexcept;
    };

    int main()
    {
        X x;
        auto fn = boost::compat::bind_front(&X::f, &x);

        fn(1, 2); // calls x.f(1, 2)
    }

### Synopsis

    namespace boost
    {
    namespace compat
    {

    template<class F, class... A> auto bind_front(F&& f, A&&... a);

    } // namespace compat
    } // namespace boost

### bind_front

    template<class F, class... A> auto bind_front(F&& f, A&&... a);

Returns: | A function object `fn` such that `fn(b…​)` is equivalent to `invoke(f, a…​, b…​)`.

## <boost/compat/function_ref.hpp>

### Description

The header `<boost/compat/function_ref.hpp>` implements the C++26 class `std::function_ref`.

`function_ref` is a lightweight polymorphic function wrapper that only stores a pointer to the supplied Callable object and a pointer to an unspecified function, meaning it does not participate in ownership of the Callable and does not allocate. All specializations of `function_ref` satisfy TriviallyCopyable.

`function_ref` supports every combination of `const` and `noexcept` and is useful for writing higher-order functions as it can avoid a template parameter or an allocation (as `std::function` is known for).

Since `nontype_t` requires C++17 as it has a template parameter of type `auto`, the constructors taking `nontype_t<f>` are only available under C++17 or later.

### Example

    int add(int x, int y) noexcept { return x * 10 + y; }

    auto add2 = [](int x, int y) { return x * 100 + y; };

    std::vector<boost::compat::function_ref<int(int, int)>> fns;
    fns.push_back({add});
    fns.push_back({add2});

    for (auto fn : fns) {
      std::cout << fn(1, 2) << std::endl;
    }

### Synopsis

    namespace boost
    {
    namespace compat
    {

    template <class... S>
    struct function_ref;

    // cv is either `const` or empty
    // noex is either `true` or `false`
    template<class R, class... ArgTypes>
    class function_ref<R(ArgTypes...) cv noexcept(noex)>
    {
    public:

        template<class F> function_ref(F*) noexcept;
        template<class F> function_ref(F&&) noexcept;

        template<auto f> function_ref(nontype_t<f>) noexcept;
        template<auto f, class U> function_ref(nontype_t<f>, U&&) noexcept;
        template<auto f, class T> function_ref(nontype_t<f>, cv T*) noexcept;

        function_ref(const function_ref&) noexcept = default;
        function_ref& operator=(const function_ref&) noexcept = default;
        template<class T> function_ref& operator=(T) = delete;

        R operator()(ArgTypes...) const noexcept(noex);
    };

    } // namespace compat
    } // namespace boost

### Constructors

#### Function Pointer Constructor

    template<class F> function_ref(F* fn) noexcept;

Preconditions | `fn` != `nullptr`.
Effects | Constructs a `function_ref` which uses the supplied function pointer as its Callable. Calling the `function_ref` is expression-equivalent to `invoke_r<R>(f, call-args…​)`.

#### Object Constructor

    template<class F> function_ref(F&& fn) noexcept;

Effects: | Constructs a `function_ref` that stores the address of the supplied Callable object `fn`. This overload only participates in resolution when `fn` is not a pointer-to-member or pointer-to-member-function. Calling the `function_ref` is expression-equivalent to `invoke_r<R>(static_cast<cv T&>(f), call-args…​)`.

#### Pointer to Member Function Constructor

    template<auto f> function_ref(nontype_t<f>) noexcept;

Effects: | Constructs a `function_ref` using the supplied pointer to member function. This overload only participates in resolution when `f` is a pointer to member or pointer to member function. Calling the `function_ref` is expression-equivalent to `invoke_r<R>(f, call-args)`.
Example: |
    struct point { int x = 1, y = 2; };

    point p;
    compat::function_ref<int(point const&)> f(compat::nontype<&point::x>);

    BOOST_TEST_EQ(f(p), 1);

#### Bound Object Constructor

    template<auto f, class U> function_ref(nontype_t<f>, U&&) noexcept;

Effects: | Constructs a `function_ref` using the supplied pointer to member or pointer to member function and a reference to an object to bind it to. This overload only participates in resolution if `is_rvalue_reference_v<U&&>` is false.
Example: |
    struct point { int x = 1, y = 2; };

    point p;
    compat::function_ref<int()> f(compat::nontype<&point::x>, p);

    BOOST_TEST_EQ(f(), 1);

#### Bound Pointer Constructor

    template<auto f, class T> function_ref(nontype_t<f>, cv T*) noexcept;

Effects: | Constructs a `function_ref` using the supplied pointer to member or pointer to member function and a pointer to an object.
Example: |
    struct point { int x = 1, y = 2; };

    point p;
    compat::function_ref<int()> f(compat::nontype<&point::x>, &p);

    BOOST_TEST_EQ(f(), 1);

#### Copy Constructor

    function_ref(const function_ref&) noexcept = default;

Effects: | `function_ref` is a TriviallyCopyable type.

### Member Functions

#### call operator

    R operator()(ArgTypes...) const noexcept(noex);

Effects: | Invokes the underlying Callable object by forwarding the supplied arguments.

### Assignment

#### Copy Assignment

    function_ref& operator=(const function_ref&) noexcept = default;
    template<class T> function_ref& operator=(T) = delete;

Effects: | `operator=(T)` participates in overload resolution if: `T` is not the same as `function_ref` `is_pointer_v<T>` is `false`.

## <boost/compat/integer_sequence.hpp>

### Description

The header `<boost/compat/integer_sequence.hpp>` implements the C++14 utilities `std::integer_sequence`, `std::index_sequence`, `std::make_integer_sequence`, `std::make_index_sequence`, and `std::index_sequence_for`.

### Synopsis

    namespace boost
    {
    namespace compat
    {

    template<class T, T... I> struct integer_sequence;

    template<class T, T N> using make_integer_sequence = /*...*/;

    template<std::size_t... I> using index_sequence = /*...*/;

    template<std::size_t N> using make_index_sequence = /*...*/;

    template<class... T> using index_sequence_for = /*...*/;

    } // namespace compat
    } // namespace boost

### integer_sequence

    template<class T, T... I> struct integer_sequence {};

### make_integer_sequence

    template<class T, T N> using make_integer_sequence = /*...*/;

`make_integer_sequence<T, N>` is an alias for `integer_sequence<T, 0, 1, 2, …​, N-1>`.

### index_sequence

    template<std::size_t... I> using index_sequence = integer_sequence<std::size_t, I...>;

### make_index_sequence

    template<std::size_t N> using make_index_sequence = make_integer_sequence<std::size_t, N>;

### index_sequence_for

    template<class... T> using index_sequence_for = make_integer_sequence<std::size_t, sizeof...(T)>;

## <boost/compat/invoke.hpp>

### Description

The header `<boost/compat/invoke.hpp>` implements the C++17 function `std::invoke`, the C++23 function `std::invoke_r`, and the associated utilities `invoke_result_t`, `is_invocable`, `is_invocable_r`, `is_nothrow_invocable`, and `is_nothrow_invocable_r`.

`invoke(f, a…​)` generally returns `f(a…​)`, but when `f` is a pointer to member, it invokes it as if by returning `mem_fn(f)(a…​)`. This allows functions, function objects, and pointers to members to be treated uniformly by components such as `bind_front`.

`invoke_r<R>(f, a…​)` returns `invoke(f, a…​)`, converted to `R`.

### Example

    struct X
    {
        void f(int a, int b) const noexcept;
    };

    int main()
    {
        X x;
        boost::compat::invoke(&X::f, x, 1, 2); // calls x.f(1, 2)
    }

### Synopsis

    namespace boost
    {
    namespace compat
    {

    template<class F, class... A> auto invoke(F&& f, A&&... a);

    template<class F, class... A> using invoke_result_t = /*...*/;

    template<class F, class... A> struct is_invocable;

    template<class F, class... A> struct is_nothrow_invocable;

    template<class R, class F, class... A> R invoke_r(F&& f, A&&... a);

    template<class R, class F, class... A> struct is_invocable_r;

    template<class R, class F, class... A> struct is_nothrow_invocable_r;

    } // namespace compat
    } // namespace boost

### invoke

    template<class F, class... A> auto invoke(F&& f, A&&... a) noexcept(/*...*/) -> /*...*/;

Returns: | `std::forward<F>(f)(std::forward<A>(a)…​)`, when `f` is not a pointer to member; `mem_fn(f)(std::forward<A>(a)…​)`, otherwise.
Constraints: | the return expression must be valid.
Remarks: | The return type is `decltype(r)`, and the `noexcept` clause is `noexcept(noexcept(r))`, where `r` is the return expression.

### invoke_result_t

    template<class F, class... A> using invoke_result_t =
      decltype( invoke(std::declval<F>(), std::declval<A>()...) );

### is_invocable

    template<class F, class... A> struct is_invocable: public /*...*/;

The base class of `is_invocable<F, A…​>` is `std::true_type` when `invoke(std::declval<F>(), std::declval<A>()…​)` is a valid expression, `std::false_type` otherwise.

### is_nothrow_invocable

    template<class F, class... A> struct is_nothrow_invocable: public /*...*/;

The base class of `is_nothrow_invocable<F, A…​>` is `std::false_type` when `is_invocable<F, A…​>::value` is `false`, `std::integral_constant<bool, noexcept(invoke(std::declval<F>(), std::declval<A>()…​))>` otherwise.

### invoke_r

    template<class R, class F, class... A> R invoke_r(F&& f, A&&... a) noexcept(/*...*/);

Returns: | `static_cast<R>(invoke(std::forward<F>(f), std::forward<A>(a)…​))`, when `R` is (possibly cv-qualified) `void`; `invoke(std::forward<F>(f), std::forward<A>(a)…​)`, implicitly converted to `R`, otherwise.
Constraints: | `is_invocable<F, A…​>::value` must be `true` and, if `R` is not cv `void`, `std::is_convertible<invoke_result_t<F, A…​>, R>::value` must be `true`.
Remarks: | The `noexcept` clause is `noexcept(noexcept(static_cast<R>(invoke(std::forward<F>(f), std::forward<A>(a)…​))))`.

### is_invocable_r

    template<class R, class F, class... A> struct is_invocable: public /*...*/;

The base class of `is_invocable_r<R, F, A…​>` is `std::true_type` when `invoke_r<R>(std::declval<F>(), std::declval<A>()…​)` is a valid expression, `std::false_type` otherwise.

### is_nothrow_invocable_r

    template<class R, class F, class... A> struct is_nothrow_invocable: public /*...*/;

The base class of `is_nothrow_invocable<R, F, A…​>` is `std::false_type` when `is_invocable_r<R, F, A…​>::value` is `false`, `std::integral_constant<bool, noexcept(invoke_r<R>(std::declval<F>(), std::declval<A>()…​))>` otherwise.

## <boost/compat/latch.hpp>

### Description

The header `<boost/compat/latch.hpp>` implements, in a portable way, the C++20 `<latch>` header.

`latch` is a single-use barrier which counts downwards, enabling synchronization between a set of threads. The counter can be manually decremented by any value, but decrementing below zero causes undefined behavior. The maximum number of waiters is specified to be `boost::compat::latch::max()`.

### Example

    std::ptrdiff_t const num_threads = 16;
    boost::compat::latch l(num_threads);

    std::vector<std::thread> threads;
    for (int i = 0; i < num_threads; ++i) {
      threads.emplace_back([&l] {
        // do some preliminary work here...

        // block until all threads have reached this statement
        l.arrive_and_wait();

        // continue with further work...
      });
    }

    for (auto& t: threads) { t.join(); }

### Synopsis

    namespace boost
    {
    namespace compat
    {

    class latch {
      explicit latch(std::ptrdiff_t expected);

      latch(latch const &) = delete;
      latch &operator=(latch const &) = delete;

      ~latch() = default;

      void count_down(std::ptrdiff_t n = 1);
      bool try_wait() const noexcept;
      void wait() const;
      void arrive_and_wait(std::ptrdiff_t n = 1);

      static constexpr std::ptrdiff_t max() noexcept;
    };

    } // namespace compat
    } // namespace boost

### Constructors

#### Counter Constructor

    explicit latch(std::ptrdiff_t expected);

Preconditions: | `expected >= 0 && expected <= boost::compat::latch::max()`.
Effects: | Constructs a latch with an internal counter value of `expected`.

#### Copy Constructor

    latch(latch const &) = delete;

`latch` is not copyable or movable.

### Member Functions

#### count_down

    void count_down(std::ptrdiff_t n = 1);

Preconditions: | `n` must not be larger than the current internal counter’s value.
Effects: | Decrements the internal counter by `n`.

#### try_wait

    bool try_wait() const noexcept;

Returns a boolean indicating whether or not the latch’s internal counter has reached 0 (`true`) or not (`false`).

#### wait

    void wait() const;

Blocks the current thread until the internal counter has reached 0.

#### arrive_and_wait

    void arrive_and_wait(std::ptrdiff_t n = 1);

Preconditions: | `n` must not be larger than the current internal counter’s value.
Effects: | Decrements the internal counter by `n` and if the counter non-zero, blocks the current thread.

#### max

    static constexpr std::ptrdiff_t max() noexcept;

Returns an implementation-defined number representing the maximum amount of waiters. Currently PTRDIFF_MAX.

## <boost/compat/mem_fn.hpp>

### Description

The header `<boost/compat/mem_fn.hpp>` implements the C++11 function `std::mem_fn`.

`mem_fn(pm)`, where `pm` is a pointer to member, returns a function object that can be used to invoke the member function, or obtain a reference to the data member, using a function call syntax.

Even though `std::mem_fn` is C++11, later standards place stricter requirements on the returned function object (it needs to be SFINAE friendly and propagate `noexcept` correctly.) `boost::compat::mem_fn` implements these stricter requirements.

### Example

    struct X
    {
        void f(int a, int b) const noexcept;
    };

    int main()
    {
        auto fn = boost::compat::mem_fn(&X::f);

        X x;
        fn(x, 1, 2); // calls x.f(1, 2)
    }

### Synopsis

    namespace boost
    {
    namespace compat
    {

    template<class M, class T> auto mem_fn(M T::* pm) noexcept;

    } // namespace compat
    } // namespace boost

### mem_fn

    template<class M, class T> auto mem_fn(M T::* pm) noexcept;

Returns: | A function object `fn` such that: `fn(x, a…​)` is equivalent to `(x.*pm)(a…​)`, when `M` is a function type and the type of `X` is `T` or derived from `T`; `fn(x, a…​)` is equivalent to `((*x).*pm)(a…​)`, when `M` is a function type and the type of `X` is not `T` or derived from `T`; `fn(x)` is equivalent to `x.*pm`, when `M` is an object type and the type of `X` is `T` or derived from `T`; `fn(x)` is equivalent to `(*x).*pm`, when `M` is an object type and the type of `X` is not `T` or derived from `T`.

## <boost/compat/move_only_function.hpp>

### Description

The header `<boost/compat/move_only_function.hpp>` implements the C++23 class std::move_only_function.

`move_only_function` is a polymorphic wrapper that stores and manages a Callable, only requiring that the type supports move construction and move assignment. This is in contrast to the commonly used `std::function` which requires copyability of the underlying managed object.

`move_only_function` supports every combination of `const`, `noexcept` and reference qualification (none, `&`, `&&`).

### Example

    struct moveonly
    {
        std::unique_ptr<int> p_ = std::make_unique<int>( 1234 );
        auto operator()( int x ) noexcept { return *p_ + x; }
    };

    boost::compat::move_only_function<int( int ) noexcept> f( moveonly{} );
    std::cout << f( 4321 ) << std::endl;

### Synopsis

    namespace boost {
    namespace compat {

    template<class... S>
    class move_only_function;

    template< class T >
    struct in_place_type_t { explicit in_place_type_t() = default; };

    template<class R, class ...Args>
    class move_only_function<R( Args... ) /* cv */ /* ref */ noexcept( /* noex */)>
    {
        move_only_function() noexcept;
        move_only_function( std::nullptr_t ) noexcept;

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

        template<class T, class ...CArgs>
        explicit move_only_function( in_place_type_t<T>, CArgs&& ... args );

        template<class T, class U, class ...CArgs>
        explicit move_only_function( in_place_type_t<T>,
                                     std::initializer_list<U> il, CArgs&& ... args );

        move_only_function( move_only_function const& ) = delete;
        move_only_function( move_only_function&& ) = default;

        ~move_only_function() = default;

        move_only_function& operator=( move_only_function&& rhs );
        move_only_function& operator=( std::nullptr_t ) noexcept;
        template<class F> move_only_function& operator=( F&& f );

        friend bool operator==( move_only_function const& fn, std::nullptr_t ) noexcept;
        friend bool operator!=( move_only_function const& fn, std::nullptr_t ) noexcept;

        void swap( move_only_function& rhs ) noexcept;
        friend void swap( move_only_function& lhs, move_only_function& rhs ) noexcept;

        explicit operator bool() const noexcept;

        R operator()( Args... args ) /* cv */ /* ref */ noexcept( /* noex */ );
    };

    } // namespace compat
    } // namespace boost

### Constructors

#### Default Constructor

    move_only_function() noexcept;

Effects | Constructs an empty `move_only_function` which manages no object.

#### Null Constructor

    move_only_function( std::nullptr_t ) noexcept;

Effects | Explicitly constructs an empty `move_only_function` using a nullptr value. Equivalent to default construction.

#### Object Constructor

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

Effects: | Given `using VT = decay_t<F>`, directly constructs an instance of `VT` using `forward<F>(f)` and stores it as the target object. If `F` is an empty function pointer, pointer-to-member or specialization of `move_only_function` then the constructed `move_only_function` is empty.
Constraints: | `remove_cv_ref<F>` is not the same type as `move_only_function` `remove_cv_ref<F>` is not a specialization of `in_place_type_t` `VT` must be callable with the provided cvref qualifiers and the provided argument types

#### In-Place Constructor

    template<class T, class ...CArgs>
    explicit move_only_function( in_place_type_t<T>, CArgs&& ... args );

Effects: | Constructs an object of type `T` using the provided args directly, storing it as the target object.
Constraints: | `is_constructible_v<T, CArgs…​>` must be true `T` must be callable with the provided cvref qualifiers and the provided argument types

#### List In-Place Constructor

    template<class T, class U, class ...CArgs>
    explicit move_only_function( in_place_type_t<T>,
                                 std::initializer_list<U> il, CArgs&& ... args );

Effects: | Constructs an object of type `T` using the provided initializer_list and args directly, storing it as the target Callable.
Constraints: | `is_constructible_v<T, std::initializer_list<U>&, CArgs…​>` must be true `T` must be callable with the provided cvref qualifiers and the provided argument types

#### Move Constructor

    move_only_function( move_only_function&& f ) = default;

Effects | Tranfers ownership of the object managed by `f` to `*this`. After this operation completes, `f` is empty and manages no object.

### Assignment

#### Move Assignment

    move_only_function& operator=( move_only_function&& rhs );

Effects: | Releases the currently managed object and takes ownership of the object managed by `rhs`, if applicable. `rhs` is empty after move.

#### Null Assigment

    move_only_function& operator=( std::nullptr_t ) noexcept;

Effects: | Releases the currently managed object, if applicable.

#### Callable Assignment

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

Effects: | Releases the currently managed object and then does the equivalent of: `move_only_function(std::forward<F>(f)).swap(*this)`.

### Utility

#### Null Equality

    friend bool operator==( move_only_function const& fn, std::nullptr_t ) noexcept;
    friend bool operator!=( move_only_function const& fn, std::nullptr_t ) noexcept;

Effects: | Returns whether or not `fn` contains a target object.

#### Swap

    void swap( move_only_function& rhs ) noexcept;
    friend void swap( move_only_function& lhs, move_only_function& rhs ) noexcept;

Effects: | Exchanges the managed objects.

### Invocation

#### Boolean Conversion

    explicit operator bool() const noexcept;

Effects: | Returns `true` if `*this` is managing an object, or `false` if `*this` is empty.

#### Call Operator

    R operator()( Args... args ) /* cv */ /* ref */ noexcept( /* noex */ );

Preconditions: | `*this` currently manages an object.
Effects: | Invokes the underlying target object. Equivalent to:
    return INVOKE<R>(static_cast<F inv-quals>(f), std::forward<Args>(args)...);
where `f` is the target object, and inv-quals is defined by the standard: If ref is empty, let inv-quals be cv&, otherwise, let inv-quals be cv ref.

## <boost/compat/shared_lock.hpp>

### Description

The header `<boost/compat/shared_lock.hpp>` implements, in a portable way, the C++14 `std::shared_lock` class template.

The class `shared_lock` is a RAII wrapper that manages locking and unlocking the provided Mutex, provided that it implements SharedLockable.

This is the shared analog of unique_lock and calls `lock_shared()` instead of `lock()`.

### Example

    #include <boost/compat/shared_lock.hpp>

    shared_mutex m;

    // acquire the lock by calling `m.lock_shared()`
    // `m.unlock_shared()` is called automatically for us by `guard` now
    boost::compat::shared_lock<shared_mutex> guard(m);
    assert(guard.owns_lock());

### Synopsis

    namespace boost {
    namespace compat {

    template <class Mutex>
    class shared_lock;

    template <class Mutex>
    void swap( shared_lock<Mutex>& x, shared_lock<Mutex>& y ) noexcept;

    template <class Mutex>
    class shared_lock {
      using mutex_type = Mutex;

      shared_lock() noexcept = default;
      explicit shared_lock( mutex_type& m );
      shared_lock( mutex_type& m, std::defer_lock_t ) noexcept;
      shared_lock( mutex_type& m, std::try_lock_t );
      shared_lock( mutex_type& m, std::adopt_lock_t );

      ~shared_lock();

      shared_lock( const shared_lock& ) = delete;
      shared_lock& operator=( const shared_lock& ) = delete;

      shared_lock( shared_lock&& u ) noexcept;
      shared_lock& operator=( shared_lock&& u ) noexcept;

      void lock();
      bool try_lock();
      void unlock();

      void swap( shared_lock& u ) noexcept;
      mutex_type* release() noexcept;

      mutex_type* mutex() const noexcept;

      bool owns_lock() const noexcept;
      explicit operator bool() const noexcept;
    };

    } // namespace compat
    } // namespace boost

### Constructors

#### Default Constructor

    shared_lock() noexcept = default;

Postconditions: | `mutex() == nullptr` and `owns_lock() == false`.

#### Locking Constructor

    explicit shared_lock( mutex_type& m );

Effects: | Calls `m.lock_shared()`.
Postconditions: | `mutex() == std::addressof(m)` and `owns_lock() == true`.

#### Deferred Constructor

    shared_lock( mutex_type& m, std::defer_lock_t ) noexcept;

Postconditions: | `mutex() == std::addressof(m)` and `owns_lock() == false`.

#### Try-to-Lock Constructor

    shared_lock( mutex_type& m, std::try_lock_t );

Effects: | Calls `m.try_lock_shared()`.
Postconditions: | `mutex() == std::addressof(m)` and `owns_lock() == res` where `res` is the result of the `m.try_lock_shared()` call.

#### Adopting Constructor

    shared_lock( mutex_type& m, std::adopt_lock_t );

Preconditions: | `m` must be held by a previous call to `m.lock_shared()` or a successful call to `m.try_lock_shared()`.
Postconditions: | `mutex() == std::addressof(m)` and `owns_lock() == true`.

#### Copy Constructor

    shared_lock( const shared_lock& ) = delete;

`shared_lock` is not copyable.

#### Move Constructor

    shared_lock( shared_lock&& u ) noexcept;

Postconditions: | `mutex() == s.mutex()` and `owns_lock() == s.owns_lock()` where `s` is the state of `u` before move. `u.mutex() == nullptr` and `u.owns_lock() == false` after move.

### Assignment

#### Copy Assignment

    shared_lock& operator=( const shared_lock& ) = delete;

`shared_lock` is not copyable.

#### Move Assignment

    shared_lock& operator=( shared_lock&& u ) noexcept;

Effects: | If `owns_lock() == true`, calls `unlock()`.
Postconditions: | `mutex() == s.mutex()` and `owns_lock() == s.owns_lock()` where `s` is the state of `u` before move. `u.mutex() == nullptr` and `u.owns_lock() == false` after move.

### Destructor

    ~shared_lock();

Effects: | If `owns_lock() == true`, calls `unlock()`.

### Member Functions

#### Locking

##### lock

    void lock();

Effects: | Calls `mutex()->lock_shared()`.
Postconditions: | `owns_lock() == true`.
Throws: | Any exception caused by `mutex()->lock_shared()`. `std::system_error` when `mutex() == nullptr` (with `std::errc::operation_not_permitted`) or `owns_lock() == true` (with `std::errc::resource_deadlock_would_occur`).

##### try_lock

    bool try_lock();

Effects: | Calls `mutex()->try_lock_shared()`.
Postconditions: | `owns_lock() == res` where `res = mutex()->try_lock_shared()`.
Throws: | Any exception caused by `mutex()->try_lock_shared()`. `std::system_error` when `mutex() == nullptr` (with `std::errc::operation_not_permitted`) or `owns_lock() == true` (with `std::errc::resource_deadlock_would_occur`).

##### unlock

    void unlock();

Effects: | Calls `mutex()->unlock_shared()`.
Postconditions: | `owns_lock() == false`.
Throws: | `std::system_error` (with `std::errc::operation_not_permitted`) if `owns_lock() == false`.

#### Modifiers

##### swap

    void swap( shared_lock& u ) noexcept;

Effects: | Swaps the data members of `*this` and `u`.

##### release

    mutex_type* release() noexcept;

Postconditions: | `mutex() == nullptr` and `owns_lock() == false`.
Returns: | The previous value of `mutex()`.

##### Free Function swap

    template <class Mutex>
    void swap( shared_lock<Mutex>& x, shared_lock<Mutex>& y ) noexcept;

Effects: | Swaps the data members of `x` and `y` via `x.swap(y)`.

#### Observers

##### mutex

    mutex_type* mutex() const noexcept;

Returns: | The value of the internal pointer, either `nullptr` or the address of the mutex.

##### owns_lock

    bool owns_lock() const noexcept;

Returns: | A boolean indicating whether or not the mutex is locked by the current `shared_lock` instance.

##### boolean conversion

    explicit operator bool() const noexcept;

Returns: | A boolean indicating whether or not the mutex is locked by the current `shared_lock` instance.

## <boost/compat/to_array.hpp>

### Description

The header `<boost/compat/to_array.hpp>` implements, in a portable way, the C++20 `std::to_array` function, present in the `<array>` header.

`to_array` creates a `std::array` from a single-dimensional C array, performing an element-wise copy or move.

### Example

    int input [] = {1, 2, 3};
    std::array<int, 3> output = boost::compat::to_array(input);
    assert((
        output == std::array<int, 3>{{1, 2, 3}}
    ));

### Synopsis

    namespace boost
    {
    namespace compat
    {

    template <class T, std::size_t N>
    constexpr std::array<remove_cv_t<T>, N> to_array(T (&a)[N]);

    template <class T, std::size_t N>
    constexpr std::array<remove_cv_t<T>, N> to_array(T (&&a)[N]);

    } // namespace compat
    } // namespace boost

### to_array

    template <class T, std::size_t N>
    constexpr std::array<remove_cv_t<T>, N> to_array(T (&&a)[N]);

Effects: | Creates an array of `N` elements by copying elements in `a`. For every `i` in `0, …​, N-1`, copy-initializes the i-th element in the output array from `a[i]`.
Type requirements: | `std::is_constructible_v<remove_cv_t<T>, T&> && !std::is_array_v<T>`. Otherwise, the overload is ill-formed.

    template <class T, std::size_t N>
    constexpr std::array<remove_cv_t<T>, N> to_array(T (&a)[N]);

Effects: | Creates an array of `N` elements by moving elements in `a`. For every `i` in `0, …​, N-1`, move-initializes the i-th element in the output array from `std::move(a[i])`.
Type requirements: | `std::is_constructible_v<remove_cv_t<T>, T&&> && !std::is_array_v<T>`. Otherwise, the overload is ill-formed.

## <boost/compat/to_underlying.hpp>

### Description

The header `<boost/compat/to_underlying.hpp>` implements the C++23 function std::to_underlying.

`to_underlying` is a terse way of converting a value of enumeration type to its underlying type, avoiding accidental narrowing or widening. This function is ill-formed if the given value is not of enumeration type.

### Example

    enum e : std::uint16_t
    {
        e_value = 5
    };
    auto output = boost::compat::to_underlying(e_value);
    static_assert(std::is_same<decltype(output), std::uint16_t>::value);
    assert((
        output == 5
    ));

### Synopsis

    namespace boost
    {
    namespace compat
    {

    template <class E>
    constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept;

    } // namespace compat
    } // namespace boost

### to_underlying

    template <class E>
    constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept;

Effects: | Casts the value `e` of enumeration type `E` to its underlying type. Equivalent to `static_cast<typename std::underlying_type<E>::type>(e)`.
Type requirements: | `std::is_enum<E>::value`. Otherwise, the function is ill-formed.

## <boost/compat/type_traits.hpp>

### Description

The header `<boost/compat/type_traits.hpp>` implements some of the post-C++11 additions to the standard header `<type_traits>`.

### Synopsis

    #include <type_traits>

    namespace boost
    {
    namespace compat
    {

    template<class T> using remove_const_t = typename std::remove_const<T>::type;

    template<class T> using remove_cv_t = typename std::remove_cv<T>::type;

    template<class T> using remove_reference_t = typename std::remove_reference<T>::type;

    template<class T> using remove_cvref_t = remove_cv_t<remove_reference_t<T>>;

    template<class T> using decay_t = typename std::decay<T>::type;

    template<bool B, class T = void> using enable_if_t = typename std::enable_if<B, T>::type;

    template<bool B, class T, class F> using conditional_t = typename std::conditional<B, T, F>::type;

    template<class... T> using void_t = void;

    } // namespace compat
    } // namespace boost

## Copyright and License

This documentation is copyright 2023, 2024 Peter Dimov and contributors and is distributed under the Boost Software License, Version 1.0.