1/*!
2@file
3Forward declares `boost::hana::optional`.
4
5Copyright Louis Dionne 2013-2022
6Distributed under the Boost Software License, Version 1.0.
7(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
8 */
9
10#ifndef BOOST_HANA_FWD_OPTIONAL_HPP
11#define BOOST_HANA_FWD_OPTIONAL_HPP
12
13#include <boost/hana/config.hpp>
14#include <boost/hana/detail/operators/adl.hpp>
15#include <boost/hana/fwd/core/make.hpp>
16
17
18namespace boost { namespace hana {
19 //! @ingroup group-datatypes
20 //! Optional value whose optional-ness is known at compile-time.
21 //!
22 //! An `optional` either contains a value (represented as `just(x)`), or
23 //! it is empty (represented as `nothing`). In essence, `hana::optional`
24 //! is pretty much like a `boost::optional` or the upcoming `std::optional`,
25 //! except for the fact that whether a `hana::optional` is empty or not is
26 //! known at compile-time. This can be particularly useful for returning
27 //! from a function that might fail, but whose reason for failing is not
28 //! important. Of course, whether the function will fail has to be known
29 //! at compile-time.
30 //!
31 //! This is really an important difference between `hana::optional` and
32 //! `std::optional`. Unlike `std::optional<T>{}` and `std::optional<T>{x}`
33 //! who share the same type (`std::optional<T>`), `hana::just(x)` and
34 //! `hana::nothing` do not share the same type, since the state of the
35 //! optional has to be known at compile-time. Hence, whether a `hana::just`
36 //! or a `hana::nothing` will be returned from a function has to be known
37 //! at compile-time for the return type of that function to be computable
38 //! by the compiler. This makes `hana::optional` well suited for static
39 //! metaprogramming tasks, but very poor for anything dynamic.
40 //!
41 //! @note
42 //! When you use a container, remember not to make assumptions about its
43 //! representation, unless the documentation gives you those guarantees.
44 //! More details [in the tutorial](@ref tutorial-containers-types).
45 //!
46 //!
47 //! Interoperation with `type`s
48 //! ---------------------------
49 //! When a `just` contains an object of type `T` which is a `type`,
50 //! it has a nested `::%type` alias equivalent to `T::%type`. `nothing`,
51 //! however, never has a nested `::%type` alias. If `t` is a `type`,
52 //! this allows `decltype(just(t))` to be seen as a nullary metafunction
53 //! equivalent to `decltype(t)`. Along with the `sfinae` function,
54 //! this allows `hana::optional` to interact seamlessly with
55 //! SFINAE-friendly metafunctions.
56 //! Example:
57 //! @include example/optional/sfinae_friendly_metafunctions.cpp
58 //!
59 //!
60 //! Modeled concepts
61 //! ----------------
62 //! 1. `Comparable`\n
63 //! Two `optional`s are equal if and only if they are both empty or they
64 //! both contain a value and those values are equal.
65 //! @include example/optional/comparable.cpp
66 //!
67 //! 2. `Orderable`\n
68 //! Optional values can be ordered by considering the value they are
69 //! holding, if any. To handle the case of an empty optional value, we
70 //! arbitrarily set `nothing` as being less than any other `just`. Hence,
71 //! @code
72 //! just(x) < just(y) if and only if x < y
73 //! nothing < just(anything)
74 //! @endcode
75 //! Example:
76 //! @include example/optional/orderable.cpp
77 //!
78 //! 3. `Functor`\n
79 //! An optional value can be seen as a list containing either one element
80 //! (`just(x)`) or no elements at all (`nothing`). As such, mapping
81 //! a function over an optional value is equivalent to applying it to
82 //! its value if there is one, and to `nothing` otherwise:
83 //! @code
84 //! transform(just(x), f) == just(f(x))
85 //! transform(nothing, f) == nothing
86 //! @endcode
87 //! Example:
88 //! @include example/optional/functor.cpp
89 //!
90 //! 4. `Applicative`\n
91 //! First, a value can be made optional with `lift<optional_tag>`, which
92 //! is equivalent to `just`. Second, one can feed an optional value to an
93 //! optional function with `ap`, which will return `just(f(x))` if there
94 //! is both a function _and_ a value, and `nothing` otherwise:
95 //! @code
96 //! ap(just(f), just(x)) == just(f(x))
97 //! ap(nothing, just(x)) == nothing
98 //! ap(just(f), nothing) == nothing
99 //! ap(nothing, nothing) == nothing
100 //! @endcode
101 //! A simple example:
102 //! @include example/optional/applicative.cpp
103 //! A more complex example:
104 //! @include example/optional/applicative.complex.cpp
105 //!
106 //! 5. `Monad`\n
107 //! The `Monad` model makes it easy to compose actions that might fail.
108 //! One can feed an optional value if there is one into a function with
109 //! `chain`, which will return `nothing` if there is no value. Finally,
110 //! optional-optional values can have their redundant level of optionality
111 //! removed with `flatten`. Also note that the `|` operator can be used in
112 //! place of the `chain` function.
113 //! Example:
114 //! @include example/optional/monad.cpp
115 //!
116 //! 6. `MonadPlus`\n
117 //! The `MonadPlus` model allows choosing the first valid value out of
118 //! two optional values with `concat`. If both optional values are
119 //! `nothing`s, `concat` will return `nothing`.
120 //! Example:
121 //! @include example/optional/monad_plus.cpp
122 //!
123 //! 7. `Foldable`\n
124 //! Folding an optional value is equivalent to folding a list containing
125 //! either no elements (for `nothing`) or `x` (for `just(x)`).
126 //! Example:
127 //! @include example/optional/foldable.cpp
128 //!
129 //! 8. `Searchable`\n
130 //! Searching an optional value is equivalent to searching a list
131 //! containing `x` for `just(x)` and an empty list for `nothing`.
132 //! Example:
133 //! @include example/optional/searchable.cpp
134#ifdef BOOST_HANA_DOXYGEN_INVOKED
135 template <typename ...T>
136 struct optional {
137 // 5.3.1, Constructors
138
139 //! Default-construct an `optional`. Only exists if the optional
140 //! contains a value, and if that value is DefaultConstructible.
141 constexpr optional() = default;
142
143 //! Copy-construct an `optional`.
144 //! An empty optional may only be copy-constructed from another
145 //! empty `optional`, and an `optional` with a value may only be
146 //! copy-constructed from another `optional` with a value.
147 //! Furthermore, this constructor only exists if the value
148 //! held in the `optional` is CopyConstructible.
149 optional(optional const&) = default;
150
151 //! Move-construct an `optional`.
152 //! An empty optional may only be move-constructed from another
153 //! empty `optional`, and an `optional` with a value may only be
154 //! move-constructed from another `optional` with a value.
155 //! Furthermore, this constructor only exists if the value
156 //! held in the `optional` is MoveConstructible.
157 optional(optional&&) = default;
158
159 //! Construct an `optional` holding a value of type `T` from another
160 //! object of type `T`. The value is copy-constructed.
161 constexpr optional(T const& t)
162 : value_(t)
163 { }
164
165 //! Construct an `optional` holding a value of type `T` from another
166 //! object of type `T`. The value is move-constructed.
167 constexpr optional(T&& t)
168 : value_(static_cast<T&&>(t))
169 { }
170
171 // 5.3.3, Assignment
172
173 //! Copy-assign an `optional`.
174 //! An empty optional may only be copy-assigned from another empty
175 //! `optional`, and an `optional` with a value may only be copy-assigned
176 //! from another `optional` with a value. Furthermore, this assignment
177 //! operator only exists if the value held in the `optional` is
178 //! CopyAssignable.
179 constexpr optional& operator=(optional const&) = default;
180
181 //! Move-assign an `optional`.
182 //! An empty optional may only be move-assigned from another empty
183 //! `optional`, and an `optional` with a value may only be move-assigned
184 //! from another `optional` with a value. Furthermore, this assignment
185 //! operator only exists if the value held in the `optional` is
186 //! MoveAssignable.
187 constexpr optional& operator=(optional&&) = default;
188
189 // 5.3.5, Observers
190
191 //! Returns a pointer to the contained value, or a `nullptr` if the
192 //! `optional` is empty.
193 //!
194 //!
195 //! @note Overloads of this method are provided for both the `const`
196 //! and the non-`const` cases.
197 //!
198 //!
199 //! Example
200 //! -------
201 //! @include example/optional/value.cpp
202 constexpr T* operator->();
203
204 //! Extract the content of an `optional`, or fail at compile-time.
205 //!
206 //! If `*this` contains a value, that value is returned. Otherwise,
207 //! a static assertion is triggered.
208 //!
209 //! @note
210 //! Overloads of this method are provided for the cases where `*this`
211 //! is a reference, a rvalue-reference and their `const` counterparts.
212 //!
213 //!
214 //! Example
215 //! -------
216 //! @include example/optional/value.cpp
217 constexpr T& value();
218
219 //! Equivalent to `value()`, provided for convenience.
220 //!
221 //! @note
222 //! Overloads of this method are provided for the cases where `*this`
223 //! is a reference, a rvalue-reference and their `const` counterparts.
224 //!
225 //!
226 //! Example
227 //! -------
228 //! @include example/optional/value.cpp
229 constexpr T& operator*();
230
231 //! Return the contents of an `optional`, with a fallback result.
232 //!
233 //! If `*this` contains a value, that value is returned. Otherwise,
234 //! the default value provided is returned.
235 //!
236 //! @note
237 //! Overloads of this method are provided for the cases where `*this`
238 //! is a reference, a rvalue-reference and their `const` counterparts.
239 //!
240 //!
241 //! @param default_
242 //! The default value to return if `*this` does not contain a value.
243 //!
244 //!
245 //! Example
246 //! -------
247 //! @include example/optional/value_or.cpp
248 template <typename U>
249 constexpr decltype(auto) value_or(U&& default_);
250
251 //! Equivalent to `hana::chain`.
252 template <typename ...T, typename F>
253 friend constexpr auto operator|(optional<T...>, F);
254
255 //! Equivalent to `hana::equal`
256 template <typename X, typename Y>
257 friend constexpr auto operator==(X&& x, Y&& y);
258
259 //! Equivalent to `hana::not_equal`
260 template <typename X, typename Y>
261 friend constexpr auto operator!=(X&& x, Y&& y);
262
263 //! Equivalent to `hana::less`
264 template <typename X, typename Y>
265 friend constexpr auto operator<(X&& x, Y&& y);
266
267 //! Equivalent to `hana::greater`
268 template <typename X, typename Y>
269 friend constexpr auto operator>(X&& x, Y&& y);
270
271 //! Equivalent to `hana::less_equal`
272 template <typename X, typename Y>
273 friend constexpr auto operator<=(X&& x, Y&& y);
274
275 //! Equivalent to `hana::greater_equal`
276 template <typename X, typename Y>
277 friend constexpr auto operator>=(X&& x, Y&& y);
278 };
279#else
280 template <typename ...T>
281 struct optional;
282#endif
283
284 //! Tag representing a `hana::optional`.
285 //! @relates hana::optional
286 struct optional_tag { };
287
288 //! Create an optional value.
289 //! @relates hana::optional
290 //!
291 //! Specifically, `make<optional_tag>()` is equivalent to `nothing`, and
292 //! `make<optional_tag>(x)` is equivalent to `just(x)`. This is provided
293 //! for consistency with the other `make<...>` functions.
294 //!
295 //!
296 //! Example
297 //! -------
298 //! @include example/optional/make.cpp
299#ifdef BOOST_HANA_DOXYGEN_INVOKED
300 template <>
301 constexpr auto make<optional_tag> = []([auto&& x]) {
302 return optional<std::decay<decltype(x)>::type>{forwarded(x)};
303 };
304#endif
305
306 //! Alias to `make<optional_tag>`; provided for convenience.
307 //! @relates hana::optional
308 //!
309 //!
310 //! Example
311 //! -------
312 //! @include example/optional/make.cpp
313 BOOST_HANA_INLINE_VARIABLE constexpr auto make_optional = make<optional_tag>;
314
315 //! Create an optional value containing `x`.
316 //! @relates hana::optional
317 //!
318 //!
319 //! Example
320 //! -------
321 //! @include example/optional/just.cpp
322#ifdef BOOST_HANA_DOXYGEN_INVOKED
323 constexpr auto just = [](auto&& x) {
324 return optional<std::decay<decltype(x)>::type>{forwarded(x)};
325 };
326#else
327 struct make_just_t {
328 template <typename T>
329 constexpr auto operator()(T&&) const;
330 };
331
332 BOOST_HANA_INLINE_VARIABLE constexpr make_just_t just{};
333#endif
334
335 //! An empty optional value.
336 //! @relates hana::optional
337 //!
338 //!
339 //! Example
340 //! -------
341 //! @include example/optional/nothing.cpp
342#ifdef BOOST_HANA_DOXYGEN_INVOKED
343 constexpr optional<> nothing{};
344#else
345 template <>
346 struct optional<> : detail::operators::adl<optional<>> {
347 // 5.3.1, Constructors
348 constexpr optional() = default;
349 constexpr optional(optional const&) = default;
350 constexpr optional(optional&&) = default;
351
352 // 5.3.3, Assignment
353 constexpr optional& operator=(optional const&) = default;
354 constexpr optional& operator=(optional&&) = default;
355
356 // 5.3.5, Observers
357 constexpr decltype(nullptr) operator->() const { return nullptr; }
358
359 template <typename ...dummy>
360 constexpr auto value() const;
361
362 template <typename ...dummy>
363 constexpr auto operator*() const;
364
365 template <typename U>
366 constexpr U&& value_or(U&& u) const;
367 };
368
369 BOOST_HANA_INLINE_VARIABLE constexpr optional<> nothing{};
370#endif
371
372 //! Apply a function to the contents of an optional, with a fallback
373 //! result.
374 //! @relates hana::optional
375 //!
376 //! Specifically, `maybe` takes a default value, a function and an
377 //! optional value. If the optional value is `nothing`, the default
378 //! value is returned. Otherwise, the function is applied to the
379 //! content of the `just`.
380 //!
381 //!
382 //! @param default_
383 //! A default value returned if `m` is `nothing`.
384 //!
385 //! @param f
386 //! A function called as `f(x)` if and only if `m` is an optional value
387 //! of the form `just(x)`. In that case, the result returend by `maybe`
388 //! is the result of `f`.
389 //!
390 //! @param m
391 //! An optional value.
392 //!
393 //!
394 //! Example
395 //! -------
396 //! @include example/optional/maybe.cpp
397#ifdef BOOST_HANA_DOXYGEN_INVOKED
398 constexpr auto maybe = [](auto&& default_, auto&& f, auto&& m) -> decltype(auto) {
399 if (m is a just(x)) {
400 return forwarded(f)(forwarded(x));
401 else
402 return forwarded(default_);
403 }
404 };
405#else
406 struct maybe_t {
407 template <typename Def, typename F, typename T>
408 constexpr decltype(auto) operator()(Def&&, F&& f, optional<T> const& m) const
409 { return static_cast<F&&>(f)(m.value_); }
410
411 template <typename Def, typename F, typename T>
412 constexpr decltype(auto) operator()(Def&&, F&& f, optional<T>& m) const
413 { return static_cast<F&&>(f)(m.value_); }
414
415 template <typename Def, typename F, typename T>
416 constexpr decltype(auto) operator()(Def&&, F&& f, optional<T>&& m) const
417 { return static_cast<F&&>(f)(static_cast<optional<T>&&>(m).value_); }
418
419 template <typename Def, typename F>
420 constexpr Def operator()(Def&& def, F&&, optional<> const&) const
421 { return static_cast<Def&&>(def); }
422 };
423
424 BOOST_HANA_INLINE_VARIABLE constexpr maybe_t maybe{};
425#endif
426
427 //! Calls a function if the call expression is well-formed.
428 //! @relates hana::optional
429 //!
430 //! Given a function `f`, `sfinae` returns a new function applying `f`
431 //! to its arguments and returning `just` the result if the call is
432 //! well-formed, and `nothing` otherwise. In other words, `sfinae(f)(x...)`
433 //! is `just(f(x...))` if that expression is well-formed, and `nothing`
434 //! otherwise. Note, however, that it is possible for an expression
435 //! `f(x...)` to be well-formed as far as SFINAE is concerned, but
436 //! trying to actually compile `f(x...)` still fails. In this case,
437 //! `sfinae` won't be able to detect it and a hard failure is likely
438 //! to happen.
439 //!
440 //!
441 //! @note
442 //! The function given to `sfinae` must not return `void`, since
443 //! `just(void)` does not make sense. A compilation error is
444 //! triggered if the function returns void.
445 //!
446 //!
447 //! Example
448 //! -------
449 //! @include example/optional/sfinae.cpp
450#ifdef BOOST_HANA_DOXYGEN_INVOKED
451 auto sfinae = [](auto&& f) {
452 return [perfect-capture](auto&& ...x) {
453 if (decltype(forwarded(f)(forwarded(x)...)) is well-formed)
454 return just(forwarded(f)(forwarded(x)...));
455 else
456 return nothing;
457 };
458 };
459#else
460 struct sfinae_t {
461 template <typename F>
462 constexpr decltype(auto) operator()(F&& f) const;
463 };
464
465 BOOST_HANA_INLINE_VARIABLE constexpr sfinae_t sfinae{};
466#endif
467
468 //! Return whether an `optional` contains a value.
469 //! @relates hana::optional
470 //!
471 //! Specifically, returns a compile-time true-valued `Logical` if `m` is
472 //! of the form `just(x)` for some `x`, and a false-valued one otherwise.
473 //!
474 //!
475 //! Example
476 //! -------
477 //! @include example/optional/is_just.cpp
478#ifdef BOOST_HANA_DOXYGEN_INVOKED
479 constexpr auto is_just = [](auto const& m) {
480 return m is a just(x);
481 };
482#else
483 struct is_just_t {
484 template <typename ...T>
485 constexpr auto operator()(optional<T...> const&) const;
486 };
487
488 BOOST_HANA_INLINE_VARIABLE constexpr is_just_t is_just{};
489#endif
490
491 //! Return whether an `optional` is empty.
492 //! @relates hana::optional
493 //!
494 //! Specifically, returns a compile-time true-valued `Logical` if `m` is
495 //! a `nothing`, and a false-valued one otherwise.
496 //!
497 //!
498 //! Example
499 //! -------
500 //! @include example/optional/is_nothing.cpp
501#ifdef BOOST_HANA_DOXYGEN_INVOKED
502 constexpr auto is_nothing = [](auto const& m) {
503 return m is a nothing;
504 };
505#else
506 struct is_nothing_t {
507 template <typename ...T>
508 constexpr auto operator()(optional<T...> const&) const;
509 };
510
511 BOOST_HANA_INLINE_VARIABLE constexpr is_nothing_t is_nothing{};
512#endif
513}} // end namespace boost::hana
514
515#endif // !BOOST_HANA_FWD_OPTIONAL_HPP
516

source code of boost/libs/hana/include/boost/hana/fwd/optional.hpp