1 /*! 2 @file 3 Forward declares `boost::hana::optional`. 4 5 @copyright Louis Dionne 2013-2017 6 Distributed 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 18 BOOST_HANA_NAMESPACE_BEGIN 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. optionaloptional161 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. optionaloptional167 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 <> __anona486f2d70102([auto&& x]) 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 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 __anona486f2d70202(auto&& x) 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 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 operator ->optional357 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 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> operator ()maybe_t408 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> operator ()maybe_t412 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> operator ()maybe_t416 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> operator ()maybe_t420 constexpr Def operator()(Def&& def, F&&, optional<> const&) const 421 { return static_cast<Def&&>(def); } 422 }; 423 424 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 __anona486f2d70302(auto&& f) 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 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 __anona486f2d70502(auto const& m) 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 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 __anona486f2d70602(auto const& m) 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 constexpr is_nothing_t is_nothing{}; 512 #endif 513 BOOST_HANA_NAMESPACE_END 514 515 #endif // !BOOST_HANA_FWD_OPTIONAL_HPP 516