forked from boostorg/core
Added a new boost/core/functor.hpp header.
The feader defines a new functor class template that can be used to wrap raw functions into a function object class. This is useful, for example, for integrating std::unique_ptr and unique_resource with custom deleters implemented as raw functions (e.g. in C libraries).
This commit is contained in:
+8
-1
@@ -1,12 +1,19 @@
|
||||
[/
|
||||
Copyright 2021 Peter Dimov
|
||||
Copyright 2022-2023 Andrey Semashev
|
||||
Copyright 2022-2024 Andrey Semashev
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
https://boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section Revision History]
|
||||
|
||||
[section Changes in 1.85.0]
|
||||
|
||||
* Added a new [link core.functor `boost/core/functor.hpp`] header with a `functor` class template
|
||||
for wrapping a raw function into a function object class.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Changes in 1.84.0]
|
||||
|
||||
* `boost::swap` utility function has been renamed to `boost::core::invoke_swap` to
|
||||
|
||||
@@ -55,6 +55,7 @@ criteria for inclusion is that the utility component be:
|
||||
[include exchange.qbk]
|
||||
[include explicit_operator_bool.qbk]
|
||||
[include first_scalar.qbk]
|
||||
[include functor.qbk]
|
||||
[include identity.qbk]
|
||||
[include ignore_unused.qbk]
|
||||
[include is_same.qbk]
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
[/
|
||||
/ Copyright (c) 2024 Andrey Semashev
|
||||
/
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
/]
|
||||
|
||||
[section:functor functor]
|
||||
|
||||
[simplesect Authors]
|
||||
|
||||
* Andrey Semashev
|
||||
|
||||
[endsimplesect]
|
||||
|
||||
[section Header <boost/core/functor.hpp>]
|
||||
|
||||
[note This component requires a compiler supporting C++17 or newer.]
|
||||
|
||||
The header `<boost/core/functor.hpp>` defines the `boost::core::functor` class template
|
||||
that wraps a raw function specified in its template parameter into a function object class.
|
||||
The function object forwards any arguments passed to it to the wrapped function and returns
|
||||
the result of the call.
|
||||
|
||||
The `functor` wrapper can be useful in cases when a function object class type is required,
|
||||
for example, for use with smart pointers such as `std::unique_ptr`, where the actual logic
|
||||
of the function object is already implemented as a raw function, possibly provided by a
|
||||
third party library. Since `functor` is default-constructible and does not store a pointer
|
||||
to the wrapped function internally, using `functor` is less error-prone and more efficient
|
||||
than using the pointer to function instead. For example, with `std::unique_ptr` you don't
|
||||
need to pass a pointer to the deleter function in the `std::unique_ptr` constructor, and
|
||||
the `std::unique_ptr` object does not store and invoke a pointer to the deleter function.
|
||||
With `functor`, the deleter function becomes part of the `std::unique_ptr` type, which
|
||||
prevents mixing pointers with incompatible deleters.
|
||||
|
||||
```
|
||||
void my_deleter(void* p);
|
||||
|
||||
using malloc_ptr = std::unique_ptr< char, boost::core::functor< std::free > >;
|
||||
using my_ptr = std::unique_ptr< char, boost::core::functor< my_deleter > >;
|
||||
|
||||
my_ptr create_string(std::size_t size);
|
||||
void consume_string(my_ptr&& str);
|
||||
|
||||
malloc_ptr ptr1(static_cast< char* >(std::malloc(size)));
|
||||
// ptr1 = allocate_string(size); // error, cannot convert my_ptr to malloc_ptr
|
||||
my_ptr ptr2 = create_string(size); // ok
|
||||
|
||||
// consume_string(std::move(ptr1)); // error, cannot convert malloc_ptr&& to my_ptr
|
||||
consume_string(std::move(ptr2)); // ok
|
||||
```
|
||||
|
||||
Using `functor` may also be beneficial for reducing generated code sizes. For example, in
|
||||
order to avoid storing and invoking a pointer to the deleter function in `std::shared_ptr`,
|
||||
one may be inclined to use lambda functions to wrap the deleter function call like this:
|
||||
|
||||
```
|
||||
std::shared_ptr< int > ptr(static_cast< int* >(std::malloc(sizeof(int))), [](int* p) { std::free(p); });
|
||||
```
|
||||
|
||||
The problem is that every lambda function declaration introduces a unique type, even if
|
||||
the lambda function definition matches exactly one of the previously declared lambda
|
||||
functions. Thus, if `std::shared_ptr` objects like the one above are created in multiple
|
||||
places in the program, the definition of the shared pointer counter and associated code
|
||||
and data (e.g. virtual function table) will be duplicated for each instance.
|
||||
|
||||
Replacing the lambda function with `functor` solves this problem without sacrificing
|
||||
readability or efficiency:
|
||||
|
||||
```
|
||||
std::shared_ptr< int > ptr(static_cast< int* >(std::malloc(sizeof(int))), boost::core::functor< std::free >());
|
||||
```
|
||||
|
||||
[section Synopsis]
|
||||
|
||||
```
|
||||
namespace boost::core {
|
||||
|
||||
template< auto Function >
|
||||
struct functor
|
||||
{
|
||||
template< typename... Args >
|
||||
decltype(auto) operator() (Args&&... args) const noexcept(...);
|
||||
};
|
||||
|
||||
} // namespace boost::core
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[section `template< typename... Args > decltype(auto) operator() (Args&&... args) const noexcept(...);`]
|
||||
|
||||
* *Effects:* `return Function(std::forward< Args >(args)...)`.
|
||||
* *Throws:* Nothing, unless invoking `Function` throws.
|
||||
* *Note:* This function only participates in overload resolution if `Function(std::forward< Args >(args)...)` is a valid call expression.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
Reference in New Issue
Block a user