3 Defines `boost::hana::optional`.
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)
10 #ifndef BOOST_HANA_OPTIONAL_HPP
11 #define BOOST_HANA_OPTIONAL_HPP
13 #include <boost/hana/fwd/optional.hpp>
15 #include <boost/hana/bool.hpp>
16 #include <boost/hana/config.hpp>
17 #include <boost/hana/core/tag_of.hpp>
18 #include <boost/hana/detail/decay.hpp>
19 #include <boost/hana/detail/operators/adl.hpp>
20 #include <boost/hana/detail/operators/comparable.hpp>
21 #include <boost/hana/detail/operators/monad.hpp>
22 #include <boost/hana/detail/operators/orderable.hpp>
23 #include <boost/hana/detail/wrong.hpp>
24 #include <boost/hana/functional/partial.hpp>
25 #include <boost/hana/fwd/any_of.hpp>
26 #include <boost/hana/fwd/ap.hpp>
27 #include <boost/hana/fwd/concat.hpp>
28 #include <boost/hana/fwd/core/make.hpp>
29 #include <boost/hana/fwd/empty.hpp>
30 #include <boost/hana/fwd/equal.hpp>
31 #include <boost/hana/fwd/find_if.hpp>
32 #include <boost/hana/fwd/flatten.hpp>
33 #include <boost/hana/fwd/less.hpp>
34 #include <boost/hana/fwd/lift.hpp>
35 #include <boost/hana/fwd/transform.hpp>
36 #include <boost/hana/fwd/type.hpp>
37 #include <boost/hana/fwd/unpack.hpp>
39 #include <cstddef> // std::nullptr_t
40 #include <type_traits>
44 BOOST_HANA_NAMESPACE_BEGIN
45 //////////////////////////////////////////////////////////////////////////
47 //////////////////////////////////////////////////////////////////////////
49 template <typename T, typename = typename hana::tag_of<T>::type>
50 struct nested_type { };
53 struct nested_type<T, type_tag> { using type = typename T::type; };
57 struct optional<T> : detail::operators::adl<>, detail::nested_type<T> {
58 // 5.3.1, Constructors
59 constexpr optional() = default;
60 constexpr optional(optional const&) = default;
61 constexpr optional(optional&&) = default;
63 constexpr optional(T const& t)
67 constexpr optional(T&& t)
68 : value_(static_cast<T&&>(t))
72 constexpr optional& operator=(optional const&) = default;
73 constexpr optional& operator=(optional&&) = default;
76 constexpr T const* operator->() const { return &value_; }
77 constexpr T* operator->() { return &value_; }
79 constexpr T& value() & { return value_; }
80 constexpr T const& value() const& { return value_; }
81 constexpr T&& value() && { return static_cast<T&&>(value_); }
82 constexpr T const&& value() const&& { return static_cast<T const&&>(value_); }
84 constexpr T& operator*() & { return value_; }
85 constexpr T const& operator*() const& { return value_; }
86 constexpr T&& operator*() && { return static_cast<T&&>(value_); }
87 constexpr T const&& operator*() const&& { return static_cast<T const&&>(value_); }
89 template <typename U> constexpr T& value_or(U&&) & { return value_; }
90 template <typename U> constexpr T const& value_or(U&&) const& { return value_; }
91 template <typename U> constexpr T&& value_or(U&&) && { return static_cast<T&&>(value_); }
92 template <typename U> constexpr T const&& value_or(U&&) const&& { return static_cast<T const&&>(value_); }
94 // We leave this public because it simplifies the implementation, but
95 // this should be considered private by users.
100 template <typename ...dummy>
101 constexpr auto optional<>::value() const {
102 static_assert(detail::wrong<dummy...>{},
103 "hana::optional::value() requires a non-empty optional");
106 template <typename ...dummy>
107 constexpr auto optional<>::operator*() const {
108 static_assert(detail::wrong<dummy...>{},
109 "hana::optional::operator* requires a non-empty optional");
112 template <typename U>
113 constexpr U&& optional<>::value_or(U&& u) const {
114 return static_cast<U&&>(u);
117 template <typename T>
118 constexpr auto make_just_t::operator()(T&& t) const {
119 return hana::optional<typename detail::decay<T>::type>(static_cast<T&&>(t));
123 template <typename ...T>
124 struct tag_of<optional<T...>> {
125 using type = optional_tag;
128 //////////////////////////////////////////////////////////////////////////
129 // make<optional_tag>
130 //////////////////////////////////////////////////////////////////////////
132 struct make_impl<optional_tag> {
133 template <typename X>
134 static constexpr auto apply(X&& x)
135 { return hana::just(static_cast<X&&>(x)); }
137 static constexpr auto apply()
138 { return hana::nothing; }
141 //////////////////////////////////////////////////////////////////////////
143 //////////////////////////////////////////////////////////////////////////
146 struct comparable_operators<optional_tag> {
147 static constexpr bool value = true;
150 struct orderable_operators<optional_tag> {
151 static constexpr bool value = true;
154 struct monad_operators<optional_tag> {
155 static constexpr bool value = true;
159 //////////////////////////////////////////////////////////////////////////
160 // is_just and is_nothing
161 //////////////////////////////////////////////////////////////////////////
163 template <typename ...T>
164 constexpr auto is_just_t::operator()(optional<T...> const&) const
165 { return hana::bool_c<sizeof...(T) != 0>; }
167 template <typename ...T>
168 constexpr auto is_nothing_t::operator()(optional<T...> const&) const
169 { return hana::bool_c<sizeof...(T) == 0>; }
172 //////////////////////////////////////////////////////////////////////////
174 //////////////////////////////////////////////////////////////////////////
177 template <typename F, typename ...X, typename = decltype(
178 std::declval<F>()(std::declval<X>()...)
180 constexpr decltype(auto) operator()(int, F&& f, X&& ...x) const {
181 using Return = decltype(static_cast<F&&>(f)(static_cast<X&&>(x)...));
182 static_assert(!std::is_same<Return, void>::value,
183 "hana::sfinae(f)(args...) requires f(args...) to be non-void");
185 return hana::just(static_cast<F&&>(f)(static_cast<X&&>(x)...));
188 template <typename F, typename ...X>
189 constexpr auto operator()(long, F&&, X&& ...) const
190 { return hana::nothing; }
195 template <typename F>
196 constexpr decltype(auto) sfinae_t::operator()(F&& f) const {
197 return hana::partial(detail::sfinae_impl{}, int{},
198 static_cast<F&&>(f));
202 //////////////////////////////////////////////////////////////////////////
204 //////////////////////////////////////////////////////////////////////////
206 struct equal_impl<optional_tag, optional_tag> {
207 template <typename T, typename U>
208 static constexpr auto apply(hana::optional<T> const& t, hana::optional<U> const& u)
209 { return hana::equal(t.value_, u.value_); }
211 static constexpr hana::true_ apply(hana::optional<> const&, hana::optional<> const&)
214 template <typename T, typename U>
215 static constexpr hana::false_ apply(T const&, U const&)
219 //////////////////////////////////////////////////////////////////////////
221 //////////////////////////////////////////////////////////////////////////
223 struct less_impl<optional_tag, optional_tag> {
224 template <typename T>
225 static constexpr hana::true_ apply(hana::optional<> const&, hana::optional<T> const&)
228 static constexpr hana::false_ apply(hana::optional<> const&, hana::optional<> const&)
231 template <typename T>
232 static constexpr hana::false_ apply(hana::optional<T> const&, hana::optional<> const&)
235 template <typename T, typename U>
236 static constexpr auto apply(hana::optional<T> const& x, hana::optional<U> const& y)
237 { return hana::less(x.value_, y.value_); }
240 //////////////////////////////////////////////////////////////////////////
242 //////////////////////////////////////////////////////////////////////////
244 struct transform_impl<optional_tag> {
245 template <typename F>
246 static constexpr auto apply(optional<> const&, F&&)
247 { return hana::nothing; }
249 template <typename T, typename F>
250 static constexpr auto apply(optional<T> const& opt, F&& f)
251 { return hana::just(static_cast<F&&>(f)(opt.value_)); }
253 template <typename T, typename F>
254 static constexpr auto apply(optional<T>& opt, F&& f)
255 { return hana::just(static_cast<F&&>(f)(opt.value_)); }
257 template <typename T, typename F>
258 static constexpr auto apply(optional<T>&& opt, F&& f)
259 { return hana::just(static_cast<F&&>(f)(static_cast<T&&>(opt.value_))); }
262 //////////////////////////////////////////////////////////////////////////
264 //////////////////////////////////////////////////////////////////////////
266 struct lift_impl<optional_tag> {
267 template <typename X>
268 static constexpr auto apply(X&& x)
269 { return hana::just(static_cast<X&&>(x)); }
273 struct ap_impl<optional_tag> {
274 template <typename F, typename X>
275 static constexpr auto ap_helper(F&&, X&&, ...)
276 { return hana::nothing; }
278 template <typename F, typename X>
279 static constexpr auto ap_helper(F&& f, X&& x, hana::true_, hana::true_)
280 { return hana::just(static_cast<F&&>(f).value_(static_cast<X&&>(x).value_)); }
282 template <typename F, typename X>
283 static constexpr auto apply(F&& f, X&& x) {
284 return ap_impl::ap_helper(static_cast<F&&>(f), static_cast<X&&>(x),
285 hana::is_just(f), hana::is_just(x));
289 //////////////////////////////////////////////////////////////////////////
291 //////////////////////////////////////////////////////////////////////////
293 struct flatten_impl<optional_tag> {
294 static constexpr auto apply(optional<> const&)
295 { return hana::nothing; }
297 static constexpr auto apply(optional<optional<>> const&)
298 { return hana::nothing; }
300 template <typename T>
301 static constexpr auto apply(optional<optional<T>> const& opt)
302 { return hana::just(opt.value_.value_); }
304 template <typename T>
305 static constexpr auto apply(optional<optional<T>>&& opt)
306 { return hana::just(static_cast<T&&>(opt.value_.value_)); }
309 //////////////////////////////////////////////////////////////////////////
311 //////////////////////////////////////////////////////////////////////////
313 struct concat_impl<optional_tag> {
314 template <typename Y>
315 static constexpr auto apply(hana::optional<>&, Y&& y)
316 { return static_cast<Y&&>(y); }
318 template <typename Y>
319 static constexpr auto apply(hana::optional<>&&, Y&& y)
320 { return static_cast<Y&&>(y); }
322 template <typename Y>
323 static constexpr auto apply(hana::optional<> const&, Y&& y)
324 { return static_cast<Y&&>(y); }
326 template <typename X, typename Y>
327 static constexpr auto apply(X&& x, Y&&)
328 { return static_cast<X&&>(x); }
332 struct empty_impl<optional_tag> {
333 static constexpr auto apply()
334 { return hana::nothing; }
337 //////////////////////////////////////////////////////////////////////////
339 //////////////////////////////////////////////////////////////////////////
341 struct unpack_impl<optional_tag> {
342 template <typename T, typename F>
343 static constexpr decltype(auto) apply(optional<T>&& opt, F&& f)
344 { return static_cast<F&&>(f)(static_cast<T&&>(opt.value_)); }
346 template <typename T, typename F>
347 static constexpr decltype(auto) apply(optional<T> const& opt, F&& f)
348 { return static_cast<F&&>(f)(opt.value_); }
350 template <typename T, typename F>
351 static constexpr decltype(auto) apply(optional<T>& opt, F&& f)
352 { return static_cast<F&&>(f)(opt.value_); }
354 template <typename F>
355 static constexpr decltype(auto) apply(optional<> const&, F&& f)
356 { return static_cast<F&&>(f)(); }
359 //////////////////////////////////////////////////////////////////////////
361 //////////////////////////////////////////////////////////////////////////
364 struct optional_find_if {
365 template <typename T>
366 static constexpr auto apply(T const&)
367 { return hana::nothing; }
371 struct optional_find_if<true> {
372 template <typename T>
373 static constexpr auto apply(T&& t)
374 { return hana::just(static_cast<T&&>(t)); }
379 struct find_if_impl<optional_tag> {
380 template <typename T, typename Pred>
381 static constexpr auto apply(hana::optional<T> const& opt, Pred&& pred) {
382 constexpr bool found = decltype(static_cast<Pred&&>(pred)(opt.value_))::value;
383 return detail::optional_find_if<found>::apply(opt.value_);
386 template <typename T, typename Pred>
387 static constexpr auto apply(hana::optional<T>& opt, Pred&& pred) {
388 constexpr bool found = decltype(static_cast<Pred&&>(pred)(opt.value_))::value;
389 return detail::optional_find_if<found>::apply(opt.value_);
392 template <typename T, typename Pred>
393 static constexpr auto apply(hana::optional<T>&& opt, Pred&& pred) {
394 constexpr bool found = decltype(
395 static_cast<Pred&&>(pred)(static_cast<T&&>(opt.value_))
397 return detail::optional_find_if<found>::apply(static_cast<T&&>(opt.value_));
400 template <typename Pred>
401 static constexpr auto apply(hana::optional<> const&, Pred&&)
402 { return hana::nothing; }
406 struct any_of_impl<optional_tag> {
407 template <typename T, typename Pred>
408 static constexpr auto apply(hana::optional<T> const& opt, Pred&& pred)
409 { return static_cast<Pred&&>(pred)(opt.value_); }
411 template <typename Pred>
412 static constexpr hana::false_ apply(hana::optional<> const&, Pred&&)
415 BOOST_HANA_NAMESPACE_END
417 #endif // !BOOST_HANA_OPTIONAL_HPP