mirror of
https://github.com/boostorg/core.git
synced 2025-05-09 23:03:54 +00:00
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).
102 lines
3.7 KiB
Plaintext
102 lines
3.7 KiB
Plaintext
[/
|
|
/ 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]
|