zoo
zoo copied to clipboard
Create a template adaptor for optional semantics.
std::optional introduces inefficiencies in the case where the space for the discriminator could be employed by the alternative. In other words, the data structure in question might already have an intrinsic discriminant that an application could use without using an additional field.
I believe the phrase "the space for the discriminator could be employed by the alternative" intends to mean that a holder of an optional field may provide a discriminant.
For this to be a template adapter, there are three choices:
- The
optionalkeeps a reference to the holder (this reference may be a pointer or C++ reference), but then this pointer/reference space negates the benefit of discriminating in the holder - The
optionaloperates likeboost::intrusive_ptrthat defines an unqualified call API from the holder, however, this does not have the convenience of theoptionalmanaging destruction of the object (destructors have no arguments) hence it would not be a proper RAII design. - The
optionalmight require a helper class in the same way thatboost::intrusive_ptrallows to satisfy the intrusive pointer API by using CRTP on the helperboost::intrusive_ref_counter. The big difference is that this helper would be required. This helper would have the discriminant for the optional. This option will be investigated.
It does not work to use CRTP directly (a holder inherits from an optional template on the type and the holder) since then managing the optional value would require using the derived class, which won't be yet-constructed on construction and would be already-destroyed on destruction of the base class (the optional).
The other option of CRTP in which optional is the derived class does not work either: it would limit the design to classes that have at most one optional.
There is a crude way to implement this: a "big" template that takes as parameter the "holder" (the object where you want both the optional and the discriminant), and tacks the extra field, the optional,
template<typename OptionalType, typename TypeToExtend>
struct Optional {
TypeToExtend tte;
AlignedStorageFor<OptionalType> storage_;
};
This can be made to work with some suitable API between Optional and TypeToExtend, but it is ugly the pattern of a template that uses composition in this way.
In general, what is wanted is that the meaning of the member "optional" is determined by sibling members.
This is already problematic, let's say there is a member called optionalPresent as in
struct HasOptional {
SomeTypeWithBooleanConversion optionalPresent;
SomeWayToIndicateOptional optionalString;
};
Let's say there is a way, in the destructor of SomeWayToIndicateOptional for optionalString that it finds the way to reference member optionalPresent, so it can destroy a string if there is a string there. The problem is that then the code can change to this:
struct HasOptional {
SomeWayToIndicateOptional optionalString;
SomeTypeWithBooleanConversion optionalPresent;
};
with the order of the members reversed, then, when destroying optionalString, optionalPresent has already been destroyed.
Then, this suggests optionalPresent ought to be implemented as a base class, to guarantee the order, but then it would be intrusive, an ugly design.
It seems there is no good way to implement optional as an adaptor.
Additionally, the only way to be able to access the discriminant from the optional is by converting the address of the optional to the address of the holder, and I can only think of how to do this via the standard macro offsetof.
Thus, it seems the lesser evil is to capture these semantics of "these members control the meaning of those other members" via macros...