1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
|
In order to use tt(std::optional) objects the tthi(optional) header file must
be included.
Consider a function returning subsequent lines from a stream. That function
could be a member function reading from a stream which was opened by its
object. A first implementation of such a member function could be
verb( std::string Class::nextLine()
{
string line;
getline(d_stream, line);
return line;
}
)
Of course, this implementation is sub-optimal as tt(getline) may fail.
Common ways to handle failures in these situations are
itemization(
it() the functions return pointers to strings, which are 0 when
tt(getline) fails, and point to strings containing the lines
if tt(getline) succeeds;
it() the functions return bools and define string pointers or reference
parameters: the functions' return values indicate whether or not
tt(getline) succeeded;
it() the functions return tt(std::pair) or tt(std::tuple) objects of which
one field is a tt(bool) and the other field is a tt(std::string).
)
The standard template library offers yet another way to handle situations like
these: the template class
verb( template <typename DataType>
class optional;
)
Here, tt(DataType) refers to the name of the data type that is handled by
the tt(optional) class. Instead of returning a tt(std::string) the function
tt(nextLine) may specify a tt(std::optional<std::string>) return type:
tt(std::optional<std::string> Class::nextLine()).
The interpretation of tt(std::optional) objects is simple: either it contains
an object of its tt(DataType) or it doesn't. If it em(does) contain a
tt(DataType) object then that object is available as object instead of a
pointer to an object (which might have been dynamically allocated) of the
specified tt(DataType). At the same type the tt(optional) object can be
interpreted as a tt(bool). If the tt(optional) object contains a tt(DataType)
object the tt(optional's bool) value is tt(true). If it doesn't contain a
tt(DataType) value, then its tt(bool) value is tt(false).
The class tt(std::optional) offers the following facilities:
itemization(
it() Constructors+nl()
The default constructor (e.g., tt(std::optional<std::string> opt;))
does not contain a value;nl()
copy- and move constructors are available;nl()
objects may be constructed from values that are convertible to the
optional's tt(DataType) (e.g., an tt(optional<string>) can be
initialized from a NTBS). If the initializing value is an rvalue
reference then the tt(DataType) object is move-constructed from the
initializing value;
itt(operator=)nl()
the assignment operator can be used to reassign the tt(DataType) values
of tt(optional) objects or to reassign the tt(optional) objects from
another tt(optional) object using the same tt(DataType). Copy- and
move-assignment operators are available;
it() Accessors+nl()
tt(explicit operator bool()) and the tt(has_value()) members return
tt(true) if the tt(optional) object contains a tt(DataType) value;nl()
tt(value(), operator*(),) and tt(operator->()) return references to the
optional's tt(DataType) value. The reference is a tt(const) reference
if called from an tt(optional<DataType> const) object; it is an
rvalue-reference if called from an rvalue reference to an
tt(optional<DataType>) object. Notes:
itemization(
it() the tt(operator*) and
tt(operator->) members act like tt(value), but do not imply
that the tt(optional's DataType) member itself is stored as a
pointer;
itt(value()) checks whether the tt(optional) object actually
contains a tt(DataType) object, and throws a
tt(std::bad_optional_access) exception if not.
)
tt(value_or(Type &&defaultValue)) returns a copy of the tt(optional)
object's tt(DataType) if the object contains a value or returns
tt(DataType{ defaultValue }) if not. Note that tt(DataType) must be
constructible from tt(Type);
it() Modifiers+nl()
tt(swap(optional<DataType> &other)): swaps the current and other
tt(optional) objects' content.nl()
tt(reset()): erases the tt(optional's DataType) member. Following
tt(reset() has_value()) returns tt(false).nl()
tt(emplace(Args &&...args), emplace(initialize_list, Args &&...args)):
the first tt(emplace) forwards tt(args) to tt(DataType's) constructor;
the second tt(emplace) forwards tt(args) to the initializer_list, and
forwards that list to tt(DataType's) constructor;
it() Comparison operators+nl()
all comparison operators (including tt(operator<=>)) are available (if
defined for the tt(optional's DataType)) to compare the tt(DataType)
objects of two tt(optional) objects;
itt(std::optional<DataType> make_optional(...))nl()
returns an tt(optional) object constructed from a tt(DataType) lvalue
or rvalue reference, or constructed from the same arguments that are
accepted by tt(emplace).
)
Here is the implementation of a function tt(nextLine), using
tt(std::optional<std::string>) and a simple tt(main) function illustrating its
workings:
verbinsert(-as4 examples/optional.cc)
The ouput of this program is:
verb( internal: has value: 1, value = hello world
main: has value: 1, value = hello world
internal: has value: 0, value =
main: has value: 0, value = hello world
)
Note that after the 2nd call, when no value is returned, tt(opt) has kept the
value it received at the first call: tt(optional's) assignment operator
doesn't bother about values already present in their objects once it notices
that tt(has_value) will return tt(false). So be sure to inspect tt(has_value)
or tt(operator bool) before calling tt(value).
|