BDE 4.14.0 Production release
|
Classes | |
class | bdef_Function< PROTOTYPE > |
Provide a polymorphic function object with a specific prototype.
Canonical header: bsl_functional.h
This component provides a single class template, bsl::function
, implementing the standard template std::function
, a runtime-polymorphic wrapper that encapsulates an arbitrary callable object (the target) and allows the wrapped object to be invoked. bsl::function
extends std::function
by adding allocator support in a manner consistent with standards proposal P0987 (http://wg21.link/P0987).
Objects of type bsl::function
generalize the notion of function pointers and are generally used to pass callbacks to a non-template function or class. For example, bsl::function<RET (ARG1, ARG2, ...)>
can be used similarly to RET (*)(ARG1, ARG2, ...)
but, unlike the function pointer, the bsl::function
can hold a non-function callable type such as pointer to member function, pointer to member data, lambda expression, or functor (class type having an operator()
). A bsl::function
can also be "empty", i.e., having no target object. In a bool
context, a bsl::function
object will evaluate to false if it is empty, and true otherwise. The target type is determined at runtime using type erasure in the constructors and can be changed by means of assignment, but the function prototype (argument types and return type) is specified as a template parameter at compile time.
An instantiation of bsl::function
is an in-core value-semantic type whose salient attributes are the type and value of its target, if any. The bsl::function
owns the target object and manages its lifetime; copying or moving the bsl::function
object copies or moves the target and destroying the bsl::function
destroys the target. Somewhat counter-intuitively, the target is always mutable within the bsl::function
; when wrapping a class type, calling a bsl::function
can modify its target object, even if the bsl::function
itself is const-qualified.
Although, as a value-semantic type, bsl::function
does have an abstract notion of "value", there is no general equality operator comparing between two bsl::function
objects. This limitation is a consequence of the target type not being required to provide equality comparison operators. The operator==
overloads that are provided compare a bsl::function
against the null pointer and do not satisfy the requirements we typically expect for value-semantic equality operators.
Calling an empty bsl::function
object will cause it to throw a bsl::bad_function_call
exception. Given a non-empty object of type bsl::function<RET(ARG0, ARG1, ...)>
invoked with arguments arg0
, arg1
, ..., invocation of the target follows the definition of INVOKE in section [func.require] of the C++ standard. These rules are summarized in the following table:
The arguments to f
must be implicitly convertible from the corresponding argument types ARG0
, ARG1
, ... and the return value of the call expression must be implicitly convertible to RET
, unless RET
is void
.
In the case of a pointer to member function, R (T::*f)(...)
, or pointer to data member R T::*f
, arg0X
is one of the following:
arg0
if ARG0
is T
or derived from T
arg0.get()
if ARG0
is a specialization of reference_wrapper(*arg0)
if ARG0
is a pointer type or pointer-like type (e.g., a smart pointer).Note that, consistent with the C++ Standard definition of INVOKE, we consider pointer-to-member-function and pointer-to-member-data types to be "callable" even though, strictly speaking, they cannot be called directly due to the lack of an operator()
.
The C++11 standard specified a type erasure scheme for allocator support in std::function
. This specification was never implemented by any vendor or popular open-source standard library and allocator support was removed from the 2017 standard version of std::function
. A new design for allocator support using std::pmr::polymorphic_allocator
instead of type erasure is currently part of version 3 of the Library Fundamentals Technical Specification (LFTS 3), after acceptance of paper P0987 (http://wg21.link/P0987). This component follows the P0987 specification, substituting bsl::allocator
for std::pmr::polymorphic_allocator
.
bsl::function
meets the requirements for an allocator-aware type. Specifically:
allocator_type
is an alias for bsl::allocator<char>
,bsl::allocator_arg_t
leading-allocator argument convention.get_allocator()
returns the allocator specified at construction.There are two uses for the allocator in bsl::function
:
A bsl::function
class has a buffer capable of holding a small callable object without allocating dynamic memory. The buffer is guaranteed to be large enough to hold a pointer to function, pointer to member function, pointer to member data, a bsl::reference_wrapper
, or a stateless functor. In practice, it is large enough to hold many stateful functors up to six times the size of a void *
. Note that, even if the target object is stored in the small object buffer, memory might still be allocated by the target object itself.
There are only two circumstances under which bsl::function
will store the target object in allocated memory:
The second restriction allows the move constructor and swap operation on bsl::function
to be noexcept
, as required by the C++ Standard.
In this section we show intended use of this component.
In this example, we create a single bsl::function
object, then assign it to callable objects of different types at run time.
First, we define a simple function that returns the XOR of its two integer arguments:
Next, we create a bsl::function
that takes two integers and returns an integer. Because we have not initialized the object with a target, it starts out as empty and evaluates to false in a Boolean context:
Next, we use assignment to give it the value of (a pointer to) intXor
and test that we can invoke it to get the expected result:
Next, we assign an instance of std::plus<int>
functor to funcObject
, which then holds a copy of it, and again test that we get the expected result when we invoke funcObject
.
Then, if we are using C++11 or later, we assign it to a lambda expression that multiplies its arguments:
Finally, we assign funcObject
to nullptr
, which makes it empty again:
Suppose we want to define an algorithm that performs a mutating operation on every element of an array of integers. The inputs are pointers to the first and last element to transform, a pointer to the first element into which the to write the output, and an operation that takes an integer in and produces an integer return value. Although the pointer arguments have known type (int *
), the type of the transformation operation can be anything that can be called with an integral argument and produces an integral return value. We do not want to accept this operation as a template argument, however (perhaps because our algorithm is sufficiently complex and/or proprietary that we want to keep it out of header files). We solve these disparate requirements by passing the operation as a bsl::function
object, whose type is known at compile time but which can be set to an arbitrary operation at run time:
For the purpose of illustration, myAlgorithm
is a simple loop that invokes the specified op
on each element in the input range and writes it directly to the output:
Next, we define input and output arrays to be used throughout the rest of this example:
Next, we define a function that simply negates its argument:
Then, we test our algorithm using our negation function:
Note that the prototype for negate
is not identical to the prototype used to instantiate the op
argument in myAlgorithm
. All that is required is that each argument to op
be convertible to the corresponding argument in the function and that the return type of the function be convertible to the return type of op
.
Next, we get a bit more sophisticated and define an operation that produces a running sum over its inputs. A running sum requires holding on to state, so we define a functor class for this purpose:
Then, we test myAlgorithm
with RunningSum
:
Note that RunningSum::operator()
is a mutating operation and that, within myAlgorithm
, op
is const. Even though bsl::function
owns a copy of its target, logical constness does not apply, as per the standard.
Finally, we run our tests and validate the results:
In this example, we'll simulate a simple library whereby worker threads take work items from a queue and execute them asynchronously. This simulation is single-threaded, but keeps metrics on how much work each worker accomplished so that we can get a rough idea of how much parallelism was expressed by the program.
We start by defining a work item type to be stored in our work queue. This type is simply a bsl::function
taking a WorkQueue
pointer argument and returning void
.
Next, we define a work queue class. For simplicity, we'll implement our queue as a fixed-sized circular buffer and (because this is a single-threaded simulation), ignore synchronization concerns.
Next, we'll create a worker class that represents the state of a worker thread:
Next, we implement the run
function, which removes a bsl::function
object from the work queue and then executes it, passing the work queue as the sole argument:
Now, we implement a simple scheduler containing a work queue and an array of four workers, which are run in a round-robin fashion:
Next, we implement the scheduler's run
method: which does a round-robin scheduling of the workers, allowing each to pull work off of the queue and run it. As tasks are run, they may enqueue more work. The scheduler returns when there are no more tasks in the queue.
Next, we create a job for the parallel system to execute. A popular illustration of parallel execution is the quicksort algorithm, which is a recursive algorithm whereby the input array is partitioned into a low and high half and quicksort is recursively applied, in parallel, to the two halves. We define a class that encapsulates an invocation of quicksort on an input range:
Next we implement the partition
method, using a variation of the Lomuto partition scheme:
Then we define the call operator for our task type, which performs the quicksort:
Finally, we use our scheduler and our QuickSortTask
to sort an array initially containing the integers between 1 and 31 in random order:
|
inline |
Return get_allocator().mechanism()
. Note that this function exists for BDE compatibility and is not part of the C++ Standard Library.
|
inline |
|
inline |
|
inline |
Create a function
having the same value as (i.e., wrapping a copy of the target held by) the specified original
object. Use the specified allocator
(e.g., the address of a bslma::Allocator
object) to supply memory. If allocator == original.allocator()
, this object is created as if by move construction; otherwise it is created as if by extended copy construction using allocator
.
|
inline |
Create a function
having the same value as (i.e., wrapping a copy of the target held by) the specified original
object. Optionally specify an allocator
(e.g., the address of a bslma::Allocator
object) to supply memory; otherwise, the default allocator is used.
|
inline |
Create an empty function
object. Optionally specify an allocator
(e.g., the address of a bslma::Allocator
object) to supply memory; otherwise, the default allocator is used.
|
inline |
Create a function
having the same target as the specified original
object. Use original.get_allocator()
as the allocator to supply memory. The original
object is set to empty after the new object is created. If the target qualifies for the small-object optimization (see class-level documentation), then it is move-constructed into the new object; otherwise ownership of the target is transferred without using the target's move constructor.
|
inline |
|
inline |
|
inline |
Create an empty object. Use the specified allocator
(e.g., the address of a bslma::Allocator
) to supply memory.
|
inline |
Return (a copy of) the allocator used to supply memory for this function
.
|
inline |
Return true
if this function
is empty or if it is non-empty and its target qualifies for the small-object optimization (and is thus allocated within this object's footprint); otherwise, return false.
|
inline |
Return *this
, converted to a mutable bdef_Function
reference by downcasting. The behavior is undefined unless bdef_Function<F*>
is derived from bsl::function<F>
and adds no new data members.
|
inline |
Return *this
converted to a const bdef_Function
reference by downcasting. The behavior is undefined unless bdef_Function<F*>
is derived from bsl::function<F>
and adds no new data members.
|
inline |
If this object is empty, throw bsl::bad_function_call
; otherwise invoke the target object with the specified args...
and return the result (after conversion to RET
). Note that, even though it is declared const
, this call operator can mutate the target object and is thus considered a manipulator rather than an accessor.
|
inline |
Set the target of this object to the target (if any) held by the specified rhs
object, destroy the target (if any) previously held by *this
, and return *this
. The result is equivalent to having constructed *this
from rhs
using the extended move constructor with allocator this->get_allocator()
. If an exception is thrown, rhs
will have a valid but unspecified value and *this
will not be modified. Note that an exception will never be thrown if get_allocator() == rhs.get_allocator()
.
|
inline |
Set the target of this object to a copy of the target (if any) held by the specified rhs
object, destroy the target (if any) previously held by *this
, and return *this
. The result is equivalent to having constructed *this
from rhs
using the extended copy constructor with allocator this->get_allocator()
. If an exception is thrown, *this
is not modified (i.e., copy assignment provides the strong exception guarantee).
|
inline |
|
inline |
Exchange the targets held by this function
and the specified other
function
. The behavior is undefined unless get_allocator() == other.get_allocator()
.
If TP
is the same type as the target object, returns a pointer granting modifiable access to the target; otherwise return a null pointer.
|
inline |
If TP
is the same type as the target object, returns a pointer granting read-only access to the target; otherwise return a null pointer.
const std::type_info & bsl::function< PROTOTYPE >::target_type | ( | ) | const |
Return typeid(void)
if this object is empty; otherwise typeid(FUNC)
where FUNC
is the type of the target object.