]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/optional/doc/01_quick_start.qbk
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / optional / doc / 01_quick_start.qbk
1 [/
2 Boost.Optional
3
4 Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal
5 Copyright (c) 2014 Andrzej Krzemienski
6
7 Distributed under the Boost Software License, Version 1.0.
8 (See accompanying file LICENSE_1_0.txt or copy at
9 http://www.boost.org/LICENSE_1_0.txt)
10 ]
11
12
13 [section Quick Start]
14
15 [section Optional return values]
16
17 Let's write and use a converter function that converts a `std::string` to an `int`. It is possible that for a given string (e.g. `"cat"`) there exists no value of type `int` capable of representing the conversion result. We do not consider such situation an error. We expect that the converter can be used only to check if the conversion is possible. A natural signature for this function can be:
18
19 #include <boost/optional.hpp>
20 boost::optional<int> convert(const std::string& text);
21
22 All necessary functionality can be included with one header `<boost/optional.hpp>`. The above function signature means that the function can either return a value of type `int` or a flag indicating that no value of `int` is available. This does not indicate an error. It is like one additional value of `int`. This is how we can use our function:
23
24 const std::string& text = /*... */;
25 boost::optional<int> oi = convert(text); // move-construct
26 if (oi) // contextual conversion to bool
27 int i = *oi; // operator*
28
29 In order to test if `optional` contains a value, we use the contextual conversion to type `bool`. Because of this we can combine the initialization of the optional object and the test into one instruction:
30
31 if (boost::optional<int> oi = convert(text))
32 int i = *oi;
33
34 We extract the contained value with `operator*` (and with `operator->` where it makes sense). An attempt to extract the contained value of an uninitialized optional object is an ['undefined behaviour] (UB). This implementation guards the call with `BOOST_ASSERT`. Therefore you should be sure that the contained value is there before extracting. For instance, the following code is reasonably UB-safe:
35
36 int i = *convert("100");
37
38 This is because we know that string value `"100"` converts to a valid value of `int`. If you do not like this potential UB, you can use an alternative way of extracting the contained value:
39
40 try {
41 int j = convert(text).value();
42 }
43 catch (const boost::bad_optional_access&) {
44 // deal with it
45 }
46
47 This version throws an exception upon an attempt to access a non-existent contained value. If your way of dealing with the missing value is to use some default, like `0`, there exists a yet another alternative:
48
49 int k = convert(text).value_or(0);
50
51 This uses the `atoi`-like approach to conversions: if `text` does not represent an integral number just return `0`. Finally, you can provide a callback to be called when trying to access the contained value fails:
52
53 int fallback_to_default()
54 {
55 cerr << "could not convert; using -1 instead" << endl;
56 return -1;
57 }
58
59 int l = convert(text).value_or_eval(fallback_to_default);
60
61 This will call the provided callback and return whatever the callback returns. The callback can have side effects: they will only be observed when the optional object does not contain a value.
62
63 Now, let's consider how function `convert` can be implemented.
64
65 boost::optional<int> convert(const std::string& text)
66 {
67 std::stringstream s(text);
68 int i;
69 if ((s >> i) && s.get() == std::char_traits<char>::eof())
70 return i;
71 else
72 return boost::none;
73 }
74
75 Observe the two return statements. `return i` uses the converting constructor that can create `optional<T>` from `T`. Thus constructed optional object is initialized and its value is a copy of `i`. The other return statement uses another converting constructor from a special tag `boost::none`. It is used to indicate that we want to create an uninitialized optional object.
76
77 [endsect]
78
79 [section Optional automatic variables]
80
81 We could write function `convert` in a slightly different manner, so that it has a single `return`-statement:
82
83 boost::optional<int> convert(const std::string& text)
84 {
85 boost::optional<int> ans;
86 std::stringstream s(text);
87 int i;
88 if ((s >> i) && s.get() == std::char_traits<char>::eof())
89 ans = i;
90
91 return ans;
92 }
93
94 The default constructor of `optional` creates an unitialized optional object. Unlike with `int`s you cannot have an `optional<int>` in an indeterminate state. Its state is always well defined. Instruction `ans = i` initializes the optional object. It uses the 'mixed' assignment from `int`. In general, for `optional<T>`, when an assignment from `T` is invoked, it can do two things. If the optional object is not initialized (our case here), it initializes the contained value using `T`'s copy constructor. If the optional object is already initialized, it assigns the new value to it using `T`'s copy assignment.
95 [endsect]
96
97 [section Optional data members]
98
99 Suppose we want to implement a ['lazy load] optimization. This is because we do not want to perform an expensive initialization of our `Resource` until (if at all) it is really used. We can do it this way:
100
101 class Widget
102 {
103 mutable boost::optional<const Resource> resource_;
104
105 public:
106 Widget() {}
107
108 const Resource& getResource() const // not thread-safe
109 {
110 if (resource_ == boost::none)
111 resource_.emplace("resource", "arguments");
112
113 return *resource_;
114 }
115 };
116
117 `optional`'s default constructor creates an uninitialized optional. No call to `Resource`'s default constructor is attempted. `Resource` doesn't have to be __SGI_DEFAULT_CONSTRUCTIBLE__. In function `getResource` we first check if `resource_` is initialized. This time we do not use the contextual conversion to `bool`, but a comparison with `boost::none`. These two ways are equivalent. Function `emplace` initializes the optional in-place by perfect-forwarding the arguments to the constructor of `Resource`. No copy- or move-construction is involved here. `Resource` doesn't even have to be `MoveConstructible`.
118
119 [note Function `emplace` is only available on compilers that support rvalue references and variadic templates. If your compiler does not support these features and you still need to avoid any move-constructions, use [link boost_optional.tutorial.in_place_factories In-Place Factories].]
120
121 [endsect]
122
123 [section Bypassing unnecessary default construction]
124
125 Suppose we have class `Date`, which does not have a default constructor: there is no good candidate for a default date. We have a function that returns two dates in form of a `boost::tuple`:
126
127 boost::tuple<Date, Date> getPeriod();
128
129 In other place we want to use the result of `getPeriod`, but want the two dates to be named: `begin` and `end`. We want to implement something like 'multiple return values':
130
131 Date begin, end; // Error: no default ctor!
132 boost::tie(begin, end) = getPeriod();
133
134 The second line works already, this is the capability of __BOOST_TUPLE__ library, but the first line won't work. We could set some invented initial dates, but it is confusing and may be an unacceptable cost, given that these values will be overwritten in the next line anyway. This is where `optional` can help:
135
136 boost::optional<Date> begin, end;
137 boost::tie(begin, end) = getPeriod();
138
139 It works because inside `boost::tie` a move-assignment from `T` is invoked on `optional<T>`, which internally calls a move-constructor of `T`.
140 [endsect]
141
142 [section Storage in containers]
143
144 Suppose you want to ask users to choose some number (an `int`). One of the valid responses is to choose nothing, which is represented by an uninitialized `optional<int>`. You want to make a histogram showing how many times each choice was made. You can use an `std::map`:
145
146 std::map<boost::optional<int>, int> choices;
147
148 for (int i = 0; i < LIMIT; ++i) {
149 boost::optional<int> choice = readChoice();
150 ++choices[choice];
151 }
152
153 This works because `optional<T>` is __SGI_LESS_THAN_COMPARABLE__ whenever `T` is __SGI_LESS_THAN_COMPARABLE__. In this case the state of being uninitialized is treated as a yet another value of `T`, which is compared less than any value of `T`.
154 [endsect]
155
156 [endsect]
157
158