Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a template adaptor for optional semantics. #54

Open
rambl30n opened this issue Feb 22, 2023 · 3 comments
Open

Create a template adaptor for optional semantics. #54

rambl30n opened this issue Feb 22, 2023 · 3 comments

Comments

@rambl30n
Copy link
Collaborator

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.

@thecppzoo
Copy link
Owner

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.

@thecppzoo
Copy link
Owner

For this to be a template adapter, there are three choices:

  1. The optional keeps 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
  2. The optional operates like boost::intrusive_ptr that defines an unqualified call API from the holder, however, this does not have the convenience of the optional managing destruction of the object (destructors have no arguments) hence it would not be a proper RAII design.
  3. The optional might require a helper class in the same way that boost::intrusive_ptr allows to satisfy the intrusive pointer API by using CRTP on the helper boost::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.

@thecppzoo
Copy link
Owner

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...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants