mirror of
				https://github.com/boostorg/optional.git
				synced 2025-11-04 09:41:37 +01:00 
			
		
		
		
	
		
			
	
	
		
			252 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			252 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 
								 | 
							
								[/
							 | 
						||
| 
								 | 
							
								    Boost.Optional
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    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 Development]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[section The models]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								In C++, we can ['declare] an object (a variable) of type `T`, and we can give this
							 | 
						||
| 
								 | 
							
								variable an ['initial value] (through an ['initializer]. (c.f. 8.5)).
							 | 
						||
| 
								 | 
							
								When a declaration includes a non-empty initializer (an initial value is given),
							 | 
						||
| 
								 | 
							
								it is said that the object has been initialized.
							 | 
						||
| 
								 | 
							
								If the declaration uses an empty initializer (no initial value is given), and
							 | 
						||
| 
								 | 
							
								neither default nor value initialization applies, it is said that the object is
							 | 
						||
| 
								 | 
							
								[*uninitialized]. Its actual value exist but has an ['indeterminate initial value]
							 | 
						||
| 
								 | 
							
								(c.f. 8.5.9).
							 | 
						||
| 
								 | 
							
								`optional<T>` intends to formalize the notion of initialization (or lack of it)
							 | 
						||
| 
								 | 
							
								allowing a program to test whether an object has been initialized and stating
							 | 
						||
| 
								 | 
							
								that access to the value of an uninitialized object is undefined behavior. That
							 | 
						||
| 
								 | 
							
								is, when a variable is declared as `optional<T>` and no initial value is given,
							 | 
						||
| 
								 | 
							
								the variable is ['formally] uninitialized. A formally uninitialized optional object
							 | 
						||
| 
								 | 
							
								has conceptually no value at all and this situation can be tested at runtime. It
							 | 
						||
| 
								 | 
							
								is formally ['undefined behavior] to try to access the value of an uninitialized
							 | 
						||
| 
								 | 
							
								optional. An uninitialized optional can be assigned a value, in which case its initialization state changes to initialized. Furthermore, given the formal
							 | 
						||
| 
								 | 
							
								treatment of initialization states in optional objects, it is even possible to
							 | 
						||
| 
								 | 
							
								reset an optional to ['uninitialized].
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								In C++ there is no formal notion of uninitialized objects, which means that
							 | 
						||
| 
								 | 
							
								objects always have an initial value even if indeterminate.
							 | 
						||
| 
								 | 
							
								As discussed on the previous section, this has a drawback because you need
							 | 
						||
| 
								 | 
							
								additional information to tell if an object has been effectively initialized.
							 | 
						||
| 
								 | 
							
								One of the typical ways in which this has been historically dealt with is via
							 | 
						||
| 
								 | 
							
								a special value: `EOF`, `npos`, -1, etc... This is equivalent to adding the
							 | 
						||
| 
								 | 
							
								special value to the set of possible values of a given type. This super set of
							 | 
						||
| 
								 | 
							
								`T` plus some ['nil_t]—were `nil_t` is some stateless POD-can be modeled in modern
							 | 
						||
| 
								 | 
							
								languages as a [*discriminated union] of T and nil_t. Discriminated unions are
							 | 
						||
| 
								 | 
							
								often called ['variants]. A variant has a ['current type], which in our case is either
							 | 
						||
| 
								 | 
							
								`T` or `nil_t`.
							 | 
						||
| 
								 | 
							
								Using the __BOOST_VARIANT__ library, this model can be implemented in terms of `boost::variant<T,nil_t>`.
							 | 
						||
| 
								 | 
							
								There is precedent for a discriminated union as a model for an optional value:
							 | 
						||
| 
								 | 
							
								the __HASKELL__ [*Maybe] built-in type constructor. Thus, a discriminated union
							 | 
						||
| 
								 | 
							
								`T+nil_t` serves as a conceptual foundation.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								A `variant<T,nil_t>` follows naturally from the traditional idiom of extending
							 | 
						||
| 
								 | 
							
								the range of possible values adding an additional sentinel value with the
							 | 
						||
| 
								 | 
							
								special meaning of ['Nothing].  However, this additional ['Nothing] value is largely
							 | 
						||
| 
								 | 
							
								irrelevant for our purpose since our goal is to formalize the notion of
							 | 
						||
| 
								 | 
							
								uninitialized objects and, while a special extended value can be used to convey
							 | 
						||
| 
								 | 
							
								that meaning, it is not strictly necessary in order to do so.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The observation made in the last paragraph about the irrelevant nature of the
							 | 
						||
| 
								 | 
							
								additional `nil_t` with respect to [_purpose] of `optional<T>` suggests an 
							 | 
						||
| 
								 | 
							
								alternative model: a ['container] that either has a value of `T` or nothing.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								As of this writing I don't know of any precedence for a variable-size
							 | 
						||
| 
								 | 
							
								fixed-capacity (of 1) stack-based container model for optional values, yet I
							 | 
						||
| 
								 | 
							
								believe this is the consequence of the lack of practical implementations of
							 | 
						||
| 
								 | 
							
								such a container rather than an inherent shortcoming of the container model.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								In any event, both the discriminated-union or the single-element container
							 | 
						||
| 
								 | 
							
								models serve as a conceptual ground for a class representing optional—i.e.
							 | 
						||
| 
								 | 
							
								possibly uninitialized—objects.
							 | 
						||
| 
								 | 
							
								For instance, these models show the ['exact] semantics required for a wrapper
							 | 
						||
| 
								 | 
							
								of optional values:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Discriminated-union:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								* [*deep-copy] semantics: copies of the variant implies copies of the value.
							 | 
						||
| 
								 | 
							
								* [*deep-relational] semantics: comparisons between variants matches both
							 | 
						||
| 
								 | 
							
								current types and values
							 | 
						||
| 
								 | 
							
								* If the variant's current type is `T`, it is modeling an ['initialized] optional.
							 | 
						||
| 
								 | 
							
								* If the variant's current type is not `T`, it is modeling an ['uninitialized]
							 | 
						||
| 
								 | 
							
								optional.
							 | 
						||
| 
								 | 
							
								* Testing if the variant's current type is `T` models testing if the optional
							 | 
						||
| 
								 | 
							
								is initialized
							 | 
						||
| 
								 | 
							
								* Trying to extract a `T` from a variant when its current type is not `T`, models
							 | 
						||
| 
								 | 
							
								the undefined behavior of trying to access the value of an uninitialized optional
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Single-element container:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								* [*deep-copy] semantics: copies of the container implies copies of the value.
							 | 
						||
| 
								 | 
							
								* [*deep-relational] semantics: comparisons between containers compare container
							 | 
						||
| 
								 | 
							
								size and if match, contained value
							 | 
						||
| 
								 | 
							
								* If the container is not empty (contains an object of type `T`), it is modeling
							 | 
						||
| 
								 | 
							
								an ['initialized] optional.
							 | 
						||
| 
								 | 
							
								* If the container is empty, it is modeling an ['uninitialized] optional.
							 | 
						||
| 
								 | 
							
								* Testing if the container is empty models testing if the optional is
							 | 
						||
| 
								 | 
							
								initialized
							 | 
						||
| 
								 | 
							
								* Trying to extract a `T` from an empty container models the undefined behavior
							 | 
						||
| 
								 | 
							
								of trying to access the value of an uninitialized optional
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[endsect]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[section The semantics]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Objects of type `optional<T>` are intended to be used in places where objects of
							 | 
						||
| 
								 | 
							
								type `T` would but which might be uninitialized. Hence, `optional<T>`'s purpose is
							 | 
						||
| 
								 | 
							
								to formalize the additional possibly uninitialized state.
							 | 
						||
| 
								 | 
							
								From the perspective of this role, `optional<T>` can have the same operational
							 | 
						||
| 
								 | 
							
								semantics of `T` plus the additional semantics corresponding to this special
							 | 
						||
| 
								 | 
							
								state.
							 | 
						||
| 
								 | 
							
								As such, `optional<T>` could be thought of as a ['supertype] of `T`. Of course, we 
							 | 
						||
| 
								 | 
							
								can't do that in C++, so we need to compose the desired semantics using a
							 | 
						||
| 
								 | 
							
								different mechanism.
							 | 
						||
| 
								 | 
							
								Doing it the other way around, that is, making `optional<T>` a ['subtype] of `T`
							 | 
						||
| 
								 | 
							
								is not only conceptually wrong but also impractical: it is not allowed to
							 | 
						||
| 
								 | 
							
								derive from a non-class type, such as a built-in type.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								We can draw from the purpose of `optional<T>` the required basic semantics:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								* [*Default Construction:] To introduce a formally uninitialized wrapped
							 | 
						||
| 
								 | 
							
								object.
							 | 
						||
| 
								 | 
							
								* [*Direct Value Construction via copy:] To introduce a formally initialized
							 | 
						||
| 
								 | 
							
								wrapped object whose value is obtained as a copy of some object.
							 | 
						||
| 
								 | 
							
								* [*Deep Copy Construction:] To obtain a new yet equivalent wrapped object.
							 | 
						||
| 
								 | 
							
								* [*Direct Value Assignment (upon initialized):] To assign a value to the
							 | 
						||
| 
								 | 
							
								wrapped object.
							 | 
						||
| 
								 | 
							
								* [*Direct Value Assignment (upon uninitialized):] To initialize the wrapped
							 | 
						||
| 
								 | 
							
								object with a value obtained as a copy of some object.
							 | 
						||
| 
								 | 
							
								* [*Assignment (upon initialized):] To assign to the wrapped object the value
							 | 
						||
| 
								 | 
							
								of another wrapped object.
							 | 
						||
| 
								 | 
							
								* [*Assignment (upon uninitialized):] To initialize the wrapped object with
							 | 
						||
| 
								 | 
							
								value of another wrapped object.
							 | 
						||
| 
								 | 
							
								* [*Deep Relational Operations (when supported by the type T):] To compare
							 | 
						||
| 
								 | 
							
								wrapped object values taking into account the presence of uninitialized states.
							 | 
						||
| 
								 | 
							
								* [*Value access:] To unwrap the wrapped object.
							 | 
						||
| 
								 | 
							
								* [*Initialization state query:] To determine if the object is formally
							 | 
						||
| 
								 | 
							
								initialized or not.
							 | 
						||
| 
								 | 
							
								* [*Swap:] To exchange wrapped objects. (with whatever exception safety
							 | 
						||
| 
								 | 
							
								guarantees are provided by `T`'s swap).
							 | 
						||
| 
								 | 
							
								* [*De-initialization:] To release the wrapped object (if any) and leave the
							 | 
						||
| 
								 | 
							
								wrapper in the uninitialized state.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Additional operations are useful, such as converting constructors and
							 | 
						||
| 
								 | 
							
								converting assignments, in-place construction and assignment, and safe
							 | 
						||
| 
								 | 
							
								value access via a pointer to the wrapped object or null.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[endsect]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[section The Interface]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Since the purpose of optional is to allow us to use objects with a formal
							 | 
						||
| 
								 | 
							
								uninitialized additional state, the interface could try to follow the
							 | 
						||
| 
								 | 
							
								interface of the underlying `T` type as much as possible. In order to choose
							 | 
						||
| 
								 | 
							
								the proper degree of adoption of the native `T` interface, the following must
							 | 
						||
| 
								 | 
							
								be noted: Even if all the operations supported by an instance of type `T` are
							 | 
						||
| 
								 | 
							
								defined for the entire range of values for such a type, an `optional<T>`
							 | 
						||
| 
								 | 
							
								extends such a set of values with a new value for which most
							 | 
						||
| 
								 | 
							
								(otherwise valid) operations are not defined in terms of `T`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Furthermore, since `optional<T>` itself is merely a `T` wrapper (modeling a `T`
							 | 
						||
| 
								 | 
							
								supertype), any attempt to define such operations upon uninitialized optionals
							 | 
						||
| 
								 | 
							
								will be totally artificial w.r.t. `T`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This library chooses an interface which follows from `T`'s interface only for
							 | 
						||
| 
								 | 
							
								those operations which are well defined (w.r.t the type `T`) even if any of the
							 | 
						||
| 
								 | 
							
								operands are uninitialized. These operations include: construction,
							 | 
						||
| 
								 | 
							
								copy-construction, assignment, swap and relational operations.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								For the value access operations, which are undefined (w.r.t the type `T`) when
							 | 
						||
| 
								 | 
							
								the operand is uninitialized, a different interface is chosen (which will be
							 | 
						||
| 
								 | 
							
								explained next).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Also, the presence of the possibly uninitialized state requires additional
							 | 
						||
| 
								 | 
							
								operations not provided by `T` itself which are supported by a special interface.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[heading Lexically-hinted Value Access in the presence of possibly
							 | 
						||
| 
								 | 
							
								untitialized optional objects: The operators * and ->]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								A relevant feature of a pointer is that it can have a [*null pointer value].
							 | 
						||
| 
								 | 
							
								This is a ['special] value which is used to indicate that the pointer is not
							 | 
						||
| 
								 | 
							
								referring to any object at all. In other words, null pointer values convey
							 | 
						||
| 
								 | 
							
								the notion of inexistent objects.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This meaning of the null pointer value allowed pointers to became a ['de
							 | 
						||
| 
								 | 
							
								facto] standard for handling optional objects because all you have to do
							 | 
						||
| 
								 | 
							
								to refer to a value which you don't really have is to use a null pointer
							 | 
						||
| 
								 | 
							
								value of the appropriate type. Pointers have been used for decades—from
							 | 
						||
| 
								 | 
							
								the days of C APIs to modern C++ libraries—to ['refer] to optional (that is,
							 | 
						||
| 
								 | 
							
								possibly inexistent) objects; particularly as optional arguments to a
							 | 
						||
| 
								 | 
							
								function, but also quite often as optional data members.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The possible presence of a null pointer value makes the operations that
							 | 
						||
| 
								 | 
							
								access the pointee's value possibly undefined, therefore, expressions which
							 | 
						||
| 
								 | 
							
								use dereference and access operators, such as: `( *p = 2 )` and `( p->foo() )`,
							 | 
						||
| 
								 | 
							
								implicitly convey the notion of optionality, and this information is tied to
							 | 
						||
| 
								 | 
							
								the ['syntax] of the expressions. That is, the presence of operators `*` and `->`
							 | 
						||
| 
								 | 
							
								tell by themselves —without any additional context— that the expression will
							 | 
						||
| 
								 | 
							
								be undefined unless the implied pointee actually exist.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Such a ['de facto] idiom for referring to optional objects can be formalized
							 | 
						||
| 
								 | 
							
								in the form of a concept: the __OPTIONAL_POINTEE__ concept.
							 | 
						||
| 
								 | 
							
								This concept captures the syntactic usage of operators `*`, `->` and
							 | 
						||
| 
								 | 
							
								conversion to `bool` to convey the notion of optionality.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								However, pointers are good to [_refer] to optional objects, but not particularly
							 | 
						||
| 
								 | 
							
								good to handle the optional objects in all other respects, such as initializing
							 | 
						||
| 
								 | 
							
								or moving/copying them. The problem resides in the shallow-copy of pointer
							 | 
						||
| 
								 | 
							
								semantics: if you need to effectively move or copy the object, pointers alone
							 | 
						||
| 
								 | 
							
								are not enough. The problem is that copies of pointers do not imply copies of
							 | 
						||
| 
								 | 
							
								pointees. For example, as was discussed in the motivation, pointers alone
							 | 
						||
| 
								 | 
							
								cannot be used to return optional objects from a function because the object
							 | 
						||
| 
								 | 
							
								must move outside from the function and into the caller's context.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								A solution to the shallow-copy problem that is often used is to resort to
							 | 
						||
| 
								 | 
							
								dynamic allocation and use a smart pointer to automatically handle the details
							 | 
						||
| 
								 | 
							
								of this. For example, if a function is to optionally return an object `X`, it can
							 | 
						||
| 
								 | 
							
								use `shared_ptr<X>` as the return value. However, this requires dynamic allocation
							 | 
						||
| 
								 | 
							
								of `X`. If `X` is a built-in or small POD, this technique is very poor in terms of
							 | 
						||
| 
								 | 
							
								required resources. Optional objects are essentially values so it is very
							 | 
						||
| 
								 | 
							
								convenient to be able to use automatic storage and deep-copy semantics to
							 | 
						||
| 
								 | 
							
								manipulate optional values just as we do with ordinary values. Pointers do
							 | 
						||
| 
								 | 
							
								not have this semantics, so are inappropriate for the initialization and
							 | 
						||
| 
								 | 
							
								transport of optional values, yet are quite convenient for handling the access
							 | 
						||
| 
								 | 
							
								to the possible undefined value because of the idiomatic aid present in the
							 | 
						||
| 
								 | 
							
								__OPTIONAL_POINTEE__ concept incarnated by pointers.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[heading Optional<T> as a model of OptionalPointee]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								For value access operations `optional<>` uses operators `*` and `->` to
							 | 
						||
| 
								 | 
							
								lexically warn about the possibly uninitialized state appealing to the
							 | 
						||
| 
								 | 
							
								familiar pointer semantics w.r.t. to null pointers.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[warning
							 | 
						||
| 
								 | 
							
								However, it is particularly important to note that `optional<>` objects
							 | 
						||
| 
								 | 
							
								are not pointers. [_`optional<>` is not, and does not model, a pointer].
							 | 
						||
| 
								 | 
							
								]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								For instance, `optional<>` does not have shallow-copy so does not alias:
							 | 
						||
| 
								 | 
							
								two different optionals never refer to the ['same] value unless `T` itself is
							 | 
						||
| 
								 | 
							
								a reference (but may have ['equivalent] values).
							 | 
						||
| 
								 | 
							
								The difference between an `optional<T>` and a pointer must be kept in mind,
							 | 
						||
| 
								 | 
							
								particularly because the semantics of relational operators are different:
							 | 
						||
| 
								 | 
							
								since `optional<T>` is a value-wrapper, relational operators are deep: they
							 | 
						||
| 
								 | 
							
								compare optional values; but relational operators for pointers are shallow:
							 | 
						||
| 
								 | 
							
								they do not compare pointee values.
							 | 
						||
| 
								 | 
							
								As a result, you might be able to replace `optional<T>` by `T*` on some
							 | 
						||
| 
								 | 
							
								situations but not always. Specifically, on generic code written for both,
							 | 
						||
| 
								 | 
							
								you cannot use relational operators directly, and must use the template
							 | 
						||
| 
								 | 
							
								functions __FUNCTION_EQUAL_POINTEES__ and __FUNCTION_LESS_POINTEES__ instead.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[endsect]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[endsect]
							 |