[/ / 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 ] [note This component requires a compiler supporting C++17 or newer.] The header `` 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]