|
BDE 4.14.0 Production release
|
Provide a namespace defining nullable value functions.
The bdlat_NullableValueFunctions namespace provided in this component defines parameterized functions that expose "nullable" behavior for "nullable" types. See the {bdlat} package-level documentation for a full description of "nullable" types.
The functions in this namespace allow users to:
makeValue),manipulateValue),accessValue), andisNull).A type becomes part of the bdlat "nullable" framework by creating, in the namespace where the type is defined, specializations of the following four (free) function templates:
A type becomes part of the bdlat "nullable" framework by creating, in the namespace where the type is defined, overloads of the following two (free) functions and two (free) function templates. Note that the placeholder YOUR_TYPE is not a template argument and should be replaced with the name of the type being plugged into the framework.
The "nullable" type must also define two meta-functions in the bdlat_NullableValueFunctions namespace:
IsNullableValue contains a compile-time constant value that is non-zero if the parameterized TYPE exposes "nullable" behavior, andValueType meta-function contains a typedef Type that specifies the type of the value that can be stored in the parameterized "nullable" type.Note that bdlb::NullableValue<TYPE> is already part of the bldat infrastructure for "nullable" types because this component also provides overloads of the required functions and meta-function specializations.
This section illustrates intended use of this component.
Suppose you had a type whose value could be in a "null" state.
We can now make mine::MyNullableValue expose "nullable" behavior by implementing the necessary bdlta_NullableValueFunctions for MyNullableValue inside the mine namespace and defining the required meta-functions withing the bdlat_NullableValueFunctions namespace.
First, we should forward declare all the functions that we will implement inside the mine namespace:
Then, we will implement these functions. Recall that the two (non-template) functions should be defined in some .cpp file, unless you choose to make them inline functions.
Finally, we specialize the IsNullableValue and ValueType meta-functions in the bdlat_NullableValueFunctions namespace for the mine::MyNullableValue type:
This completes the bdlat infrastructure for mine::MyNullableValue and allows the generic software to recognize the type as a nullable abstraction.
The bdlat "nullable" framework provides a set of fundamental operations common to any "nullable" type. We can build upon these operations to make our own utilities, or use them on our own types that are plugged into the framework, like mine::MyNullableValue, which we created in {Example 1}. For example, we can use the (fundamental) operations in the bdlat_NullableValueFunctions namespace to operate on mine::NullableValue, even though they have no knowledge of that type in particular:
Two of those operations are rather basic. One simply informs whether or not an object is in the null state (the isNull method). Another sets an object to a default, non-null state (the makeValue method).
The other two generic methods accomplish their actions via user-supplied functors.
Let us define a generic functor that gives us access to the underlying value of the "nullable" type, if it's not null:
Notice that the above class makes no assumptions about the value being accessed other than it can be copied (in the constructor) and assigned (in the operator).
This functor can be used to fetch the value of our nullable object:
Notice that we did not invoke accessValue until object had been set to a non-null state. Doing otherwise would have led to undefined behavior.
Finally, let's define a functor to set the state of a nullable object:
As with the previous functor, this functor has no knowledge of the nullable type to which it will be applied. The only assumption here is that the value (type) of our nullable type can be copy constructed and copy assigned.
Let us use this functor to modify one of our nullable objects:
Creating functor objects for each operation can be tedious and error prone; consequently, those types are often executed via utility functions.
Suppose we want to create utilities for getting and setting the value associated with an arbitrary "nullable" type.
These functors make minimal assumptions of VALUE_TYPE, merely that it is copy constructable and copy assignable.
Now, we can use these functors to write generic utility functions for getting and setting the value types of arbitrary "nullable" classes.
Finally, suppose we have another type such as your::YourNullableType, shown below:
Notice that while there are many similarities to mine::MyNullableValue there are clearly differences:
bsl::string, not int.Nevertheless, since your::YourNullableValue also provides the functions and types expected by the bdlat infrastructure (not shown) we can successfully use your::YourNullableValue value instead of mine::MyNullableValue in the previous usage scenario, with no other changes:
Notice that syntax and order of bdlat_NullableValueFunction functions calls have not been changed. The only difference is that the contained type has changed from int to bsl::string.
Finally, instead of defining a new "nullable" type, we could substitute the existing type template bdlb::NullableValue. Note that this component provides specializations of the bdlat_nullableValueFunctions for that type. Since the accessor and manipulator functions we created earlier are type neutral, we can simply drop bdlb::NullableValue<float> into our familiar scenario: