2 * Copyright 2017 Jacob Lifshay
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 #ifndef UTIL_OPTIONAL_H_
25 #define UTIL_OPTIONAL_H_
27 #include <type_traits>
30 #include <initializer_list>
36 #include "is_swappable.h"
44 constexpr explicit nullopt_t(int)
49 constexpr nullopt_t
nullopt(0);
51 class bad_optional_access
: public std::exception
54 virtual const char *what() const noexcept override
56 return "bad_optional_access";
63 bool Is_Trivially_Destructible
= std::is_trivially_destructible
<T
>::value
,
64 bool Is_Trivially_Copyable
= std::is_trivially_copyable
<T
>::value
>
70 alignas(T
) char empty_value
[sizeof(T
)];
73 constexpr Optional_base() noexcept
: empty_value
{}, is_full(false)
76 constexpr Optional_base(nullopt_t
) noexcept
: empty_value
{}, is_full(false)
84 template <typename
... Types
>
85 T
&emplace(Types
&&... args
) noexcept(std::is_nothrow_constructible
<T
, Types
...>::value
)
88 ::new(static_cast<void *>(std::addressof(full_value
))) T(std::forward
<Types
>(args
)...);
95 typename
= typename
std::
96 enable_if
<std::is_constructible
<T
, std::initializer_list
<U
>, Types
...>::value
>::type
>
97 T
&emplace(std::initializer_list
<U
> init_list
, Types
&&... args
) noexcept(
98 std::is_nothrow_constructible
<T
, std::initializer_list
<U
>, Types
...>::value
)
101 ::new(static_cast<void *>(std::addressof(full_value
)))
102 T(init_list
, std::forward
<Types
>(args
)...);
106 Optional_base(const Optional_base
&rt
) noexcept(std::is_nothrow_copy_constructible
<T
>::value
)
107 : empty_value
{}, is_full(false)
110 emplace(rt
.full_value
);
112 Optional_base(Optional_base
&&rt
) noexcept(std::is_nothrow_move_constructible
<T
>::value
)
113 : empty_value
{}, is_full(false)
116 emplace(std::move(rt
.full_value
));
118 template <typename
... Types
,
119 typename
= typename
std::enable_if
<std::is_constructible
<T
, Types
...>::value
>::type
>
120 constexpr explicit Optional_base(in_place_t
, Types
&&... args
) noexcept(
121 std::is_nothrow_constructible
<T
, Types
...>::value
)
122 : full_value(std::forward
<Types
>(args
)...), is_full(true)
128 typename
= typename
std::
129 enable_if
<std::is_constructible
<T
, std::initializer_list
<U
>, Types
...>::value
>::type
>
130 constexpr explicit Optional_base(
132 std::initializer_list
<U
> init_list
,
133 Types
&&... args
) noexcept(std::is_nothrow_constructible
<T
, Types
...>::value
)
134 : full_value(init_list
, std::forward
<Types
>(args
)...), is_full(true)
141 Optional_base
&operator=(const Optional_base
&rt
) noexcept(
142 std::is_nothrow_copy_assignable
<T
>::value
)
147 emplace(rt
.full_value
);
149 full_value
= rt
.full_value
;
152 Optional_base
&operator=(Optional_base
&&rt
) noexcept(std::is_nothrow_move_assignable
<T
>::value
)
157 emplace(std::move(rt
.full_value
));
159 full_value
= std::move(rt
.full_value
);
164 template <typename T
>
165 struct Optional_base
<T
, true, false>
170 alignas(T
) char empty_value
[sizeof(T
)];
173 constexpr Optional_base() noexcept
: empty_value
{}, is_full(false)
176 constexpr Optional_base(nullopt_t
) noexcept
: empty_value
{}, is_full(false)
179 void reset() noexcept
181 // full_value.~T() not needed
183 template <typename
... Types
>
184 T
&emplace(Types
&&... args
) noexcept(std::is_nothrow_constructible
<T
, Types
...>::value
)
187 ::new(static_cast<void *>(std::addressof(full_value
))) T(std::forward
<Types
>(args
)...);
194 typename
= typename
std::
195 enable_if
<std::is_constructible
<T
, std::initializer_list
<U
>, Types
...>::value
>::type
>
196 T
&emplace(std::initializer_list
<U
> init_list
, Types
&&... args
) noexcept(
197 std::is_nothrow_constructible
<T
, std::initializer_list
<U
>, Types
...>::value
)
200 ::new(static_cast<void *>(std::addressof(full_value
)))
201 T(init_list
, std::forward
<Types
>(args
)...);
205 Optional_base(const Optional_base
&rt
) noexcept(std::is_nothrow_copy_constructible
<T
>::value
)
206 : empty_value
{}, is_full(false)
209 emplace(rt
.full_value
);
211 Optional_base(Optional_base
&&rt
) noexcept(std::is_nothrow_move_constructible
<T
>::value
)
212 : empty_value
{}, is_full(false)
215 emplace(std::move(rt
.full_value
));
217 template <typename
... Types
,
218 typename
= typename
std::enable_if
<std::is_constructible
<T
, Types
...>::value
>::type
>
219 constexpr explicit Optional_base(in_place_t
, Types
&&... args
) noexcept(
220 std::is_nothrow_constructible
<T
, Types
...>::value
)
221 : full_value(std::forward
<Types
>(args
)...), is_full(true)
227 typename
= typename
std::
228 enable_if
<std::is_constructible
<T
, std::initializer_list
<U
>, Types
...>::value
>::type
>
229 constexpr explicit Optional_base(
231 std::initializer_list
<U
> init_list
,
232 Types
&&... args
) noexcept(std::is_nothrow_constructible
<T
, Types
...>::value
)
233 : full_value(init_list
, std::forward
<Types
>(args
)...), is_full(true)
236 ~Optional_base() = default;
237 Optional_base
&operator=(const Optional_base
&rt
) noexcept(
238 std::is_nothrow_copy_assignable
<T
>::value
)
243 emplace(rt
.full_value
);
245 full_value
= rt
.full_value
;
248 Optional_base
&operator=(Optional_base
&&rt
) noexcept(std::is_nothrow_move_assignable
<T
>::value
)
253 emplace(std::move(rt
.full_value
));
255 full_value
= std::move(rt
.full_value
);
260 template <typename T
>
261 struct Optional_base
<T
, true, true>
266 alignas(T
) char empty_value
[sizeof(T
)];
269 constexpr Optional_base() noexcept
: empty_value
{}, is_full(false)
272 constexpr Optional_base(nullopt_t
) noexcept
: empty_value
{}, is_full(false)
275 void reset() noexcept
277 // full_value.~T() not needed
279 template <typename
... Types
>
280 T
&emplace(Types
&&... args
) noexcept(std::is_nothrow_constructible
<T
, Types
...>::value
)
283 ::new(static_cast<void *>(std::addressof(full_value
))) T(std::forward
<Types
>(args
)...);
290 typename
= typename
std::
291 enable_if
<std::is_constructible
<T
, std::initializer_list
<U
>, Types
...>::value
>::type
>
292 T
&emplace(std::initializer_list
<U
> init_list
, Types
&&... args
) noexcept(
293 std::is_nothrow_constructible
<T
, std::initializer_list
<U
>, Types
...>::value
)
296 ::new(static_cast<void *>(std::addressof(full_value
)))
297 T(init_list
, std::forward
<Types
>(args
)...);
301 constexpr Optional_base(const Optional_base
&rt
) noexcept
= default;
302 constexpr Optional_base(Optional_base
&&rt
) noexcept
= default;
303 template <typename
... Types
,
304 typename
= typename
std::enable_if
<std::is_constructible
<T
, Types
...>::value
>::type
>
305 constexpr explicit Optional_base(in_place_t
, Types
&&... args
) noexcept(
306 std::is_nothrow_constructible
<T
, Types
...>::value
)
307 : full_value(std::forward
<Types
>(args
)...), is_full(true)
313 typename
= typename
std::
314 enable_if
<std::is_constructible
<T
, std::initializer_list
<U
>, Types
...>::value
>::type
>
315 constexpr explicit Optional_base(
317 std::initializer_list
<U
> init_list
,
318 Types
&&... args
) noexcept(std::is_nothrow_constructible
<T
, Types
...>::value
)
319 : full_value(init_list
, std::forward
<Types
>(args
)...), is_full(true)
322 ~Optional_base() = default;
323 Optional_base
&operator=(const Optional_base
&rt
) noexcept
= default;
324 Optional_base
&operator=(Optional_base
&&rt
) noexcept
= default;
328 template <typename T
>
333 template <typename T
, typename U
, typename U_Ref
>
334 constexpr bool optional_needs_conversion_constructors() noexcept
336 if(!std::is_constructible
<T
, U_Ref
>::value
)
338 if(std::is_constructible
<T
, optional
<U
> &>::value
)
340 if(std::is_constructible
<T
, const optional
<U
> &>::value
)
342 if(std::is_constructible
<T
, optional
<U
> &&>::value
)
344 if(std::is_constructible
<T
, const optional
<U
> &&>::value
)
346 if(std::is_convertible
<optional
<U
> &, T
>::value
)
348 if(std::is_convertible
<const optional
<U
> &, T
>::value
)
350 if(std::is_convertible
<optional
<U
> &&, T
>::value
)
352 if(std::is_convertible
<const optional
<U
> &&, T
>::value
)
357 template <typename T
, typename U
, typename U_Ref
>
358 constexpr bool optional_needs_conversion_from_optional_assign_operators() noexcept
360 if(!std::is_constructible
<T
, U_Ref
>::value
)
362 if(!std::is_assignable
<T
&, U_Ref
>::value
)
364 if(std::is_constructible
<T
, optional
<U
> &>::value
)
366 if(std::is_constructible
<T
, const optional
<U
> &>::value
)
368 if(std::is_constructible
<T
, optional
<U
> &&>::value
)
370 if(std::is_constructible
<T
, const optional
<U
> &&>::value
)
372 if(std::is_convertible
<optional
<U
> &, T
>::value
)
374 if(std::is_convertible
<const optional
<U
> &, T
>::value
)
376 if(std::is_convertible
<optional
<U
> &&, T
>::value
)
378 if(std::is_convertible
<const optional
<U
> &&, T
>::value
)
380 if(std::is_assignable
<T
&, optional
<U
> &>::value
)
382 if(std::is_assignable
<T
&, const optional
<U
> &>::value
)
384 if(std::is_assignable
<T
&, optional
<U
> &&>::value
)
386 if(std::is_assignable
<T
&, const optional
<U
> &&>::value
)
392 template <typename T
>
393 class optional
: private detail::Optional_base
<T
>
396 typedef detail::Optional_base
<T
> Base
;
398 using Base::full_value
;
402 using Base::operator=;
405 constexpr optional() noexcept
= default;
406 template <typename U
,
407 typename
= typename
std::
408 enable_if
<detail::optional_needs_conversion_constructors
<T
, U
, const U
&>()
409 && std::is_convertible
<const U
&, T
>::value
>::type
>
410 optional(const optional
<U
> &rt
) noexcept(std::is_nothrow_constructible
<T
, const U
&>::value
)
416 template <typename U
,
417 typename
= typename
std::
418 enable_if
<detail::optional_needs_conversion_constructors
<T
, U
, const U
&>()
419 && !std::is_convertible
<const U
&, T
>::value
>::type
,
421 explicit optional(const optional
<U
> &rt
) noexcept(
422 std::is_nothrow_constructible
<T
, const U
&>::value
)
431 typename
std::enable_if
<detail::optional_needs_conversion_constructors
<T
, U
, U
&&>()
432 && std::is_convertible
<U
&&, T
>::value
>::type
>
433 optional(optional
<U
> &&rt
) noexcept(std::is_nothrow_constructible
<T
, U
&&>::value
)
437 emplace(std::move(*rt
));
442 typename
std::enable_if
<detail::optional_needs_conversion_constructors
<T
, U
, U
&&>()
443 && !std::is_convertible
<U
&&, T
>::value
>::type
,
445 explicit optional(optional
<U
> &&rt
) noexcept(std::is_nothrow_constructible
<T
, U
&&>::value
)
449 emplace(std::move(*rt
));
451 template <typename U
,
452 typename
= typename
std::
453 enable_if
<std::is_constructible
<T
, U
&&>::value
454 && !std::is_same
<typename
std::decay
<U
>::type
, in_place_t
>::value
455 && !std::is_same
<typename
std::decay
<U
>::type
, optional
>::value
456 && std::is_convertible
<U
&&, T
>::value
>::type
,
458 constexpr optional(U
&&value
) noexcept(std::is_nothrow_constructible
<T
, U
&&>::value
)
459 : Base(in_place
, std::forward
<U
>(value
))
462 template <typename U
,
463 typename
= typename
std::
464 enable_if
<std::is_constructible
<T
, U
&&>::value
465 && !std::is_same
<typename
std::decay
<U
>::type
, in_place_t
>::value
466 && !std::is_same
<typename
std::decay
<U
>::type
, optional
>::value
467 && !std::is_convertible
<U
&&, T
>::value
>::type
>
468 explicit constexpr optional(U
&&value
) noexcept(std::is_nothrow_constructible
<T
, U
&&>::value
)
469 : Base(in_place
, std::forward
<U
>(value
))
472 template <typename U
= T
,
473 typename
= typename
std::
474 enable_if
<!std::is_same
<typename
std::decay
<U
>::type
, optional
>::value
475 && std::is_constructible
<T
, U
>::value
476 && std::is_assignable
<T
&, U
>::value
477 && (!std::is_scalar
<T
>::value
478 || !std::is_same
<typename
std::decay
<U
>::type
, T
>::value
)>::type
>
479 optional
&operator=(U
&&value
) noexcept(std::is_nothrow_constructible
<T
, U
&&>::value
480 &&std::is_nothrow_assignable
<T
&, U
&&>::value
)
483 full_value
= std::forward
<U
>(value
);
485 emplace(std::forward
<U
>(value
));
488 optional
&operator=(nullopt_t
) noexcept
495 typename
= typename
std::enable_if
< //
496 detail::optional_needs_conversion_from_optional_assign_operators
<T
, U
, const U
&>()>::
498 optional
&operator=(const optional
<U
> &rt
) noexcept(
499 std::is_nothrow_constructible
<T
, const U
&>::value
500 &&std::is_nothrow_assignable
<T
&, const U
&>::value
)
512 typename
= typename
std::enable_if
< //
513 detail::optional_needs_conversion_from_optional_assign_operators
<T
, U
, U
&&>()>::type
>
514 optional
&operator=(optional
<U
> &&rt
) noexcept(std::is_nothrow_constructible
<T
, U
&&>::value
&&
515 std::is_nothrow_assignable
<T
&, U
&&>::value
)
520 emplace(std::move(*rt
));
522 full_value
= std::move(*rt
);
525 constexpr const T
*operator->() const noexcept
528 return std::addressof(full_value
);
530 constexpr T
*operator->() noexcept
533 return std::addressof(full_value
);
535 constexpr const T
&operator*() const &noexcept
540 constexpr T
&operator*() & noexcept
545 constexpr const T
&&operator*() const &&noexcept
548 return std::move(full_value
);
550 constexpr T
&&operator*() && noexcept
553 return std::move(full_value
);
555 constexpr explicit operator bool() const noexcept
559 constexpr bool has_value() const noexcept
563 constexpr T
&value() &
566 throw bad_optional_access();
569 constexpr const T
&value() const &
572 throw bad_optional_access();
575 constexpr T
&&value() &&
578 throw bad_optional_access();
579 return std::move(full_value
);
581 constexpr const T
&&value() const &&
584 throw bad_optional_access();
585 return std::move(full_value
);
587 template <typename U
>
588 constexpr T
value_or(U
&&default_value
) const &noexcept(
589 std::is_nothrow_copy_constructible
<T
>::value
//
590 &&noexcept(static_cast<T
>(std::declval
<U
>())))
592 return is_full
? full_value
: static_cast<T
>(std::forward
<U
>(default_value
));
594 template <typename U
>
595 constexpr T
value_or(U
&&default_value
)
596 && noexcept(std::is_nothrow_copy_constructible
<T
>::value
//
597 &&noexcept(static_cast<T
>(std::declval
<U
>())))
599 return is_full
? std::move(full_value
) : static_cast<T
>(std::forward
<U
>(default_value
));
601 void swap(optional
&other
) noexcept(
602 std::is_nothrow_move_constructible
<T
>::value
&&util::is_nothrow_swappable
<T
>::value
)
609 swap(full_value
, other
.full_value
);
613 other
.emplace(std::move(full_value
));
617 else if(other
.is_full
)
619 emplace(std::move(other
.full_value
));
625 template <typename T
, typename U
>
626 constexpr bool operator==(const optional
<T
> &l
, const optional
<T
> &r
) noexcept(noexcept(*l
== *r
))
628 if(!l
.has_value() || !r
.has_value())
629 return !r
.has_value();
633 template <typename T
, typename U
>
634 constexpr bool operator!=(const optional
<T
> &l
, const optional
<T
> &r
) noexcept(noexcept(*l
== *r
))
636 if(!l
.has_value() || !r
.has_value())
637 return r
.has_value();
641 template <typename T
, typename U
>
642 constexpr bool operator<(const optional
<T
> &l
, const optional
<T
> &r
) noexcept(noexcept(*l
== *r
))
644 if(!l
.has_value() || !r
.has_value())
645 return r
.has_value();
649 template <typename T
, typename U
>
650 constexpr bool operator>(const optional
<T
> &l
, const optional
<T
> &r
) noexcept(noexcept(*l
== *r
))
652 if(!l
.has_value() || !r
.has_value())
653 return l
.has_value();
657 template <typename T
, typename U
>
658 constexpr bool operator<=(const optional
<T
> &l
, const optional
<T
> &r
) noexcept(noexcept(*l
== *r
))
660 if(!l
.has_value() || !r
.has_value())
661 return !l
.has_value();
665 template <typename T
, typename U
>
666 constexpr bool operator>=(const optional
<T
> &l
, const optional
<T
> &r
) noexcept(noexcept(*l
== *r
))
668 if(!l
.has_value() || !r
.has_value())
669 return !r
.has_value();
673 template <typename T
>
674 constexpr bool operator==(const optional
<T
> &v
, nullopt_t
) noexcept
676 return !v
.has_value();
679 template <typename T
>
680 constexpr bool operator!=(const optional
<T
> &v
, nullopt_t
) noexcept
682 return v
.has_value();
685 template <typename T
>
686 constexpr bool operator<(const optional
<T
> &v
, nullopt_t
) noexcept
691 template <typename T
>
692 constexpr bool operator>(const optional
<T
> &v
, nullopt_t
) noexcept
694 return v
.has_value();
697 template <typename T
>
698 constexpr bool operator<=(const optional
<T
> &v
, nullopt_t
) noexcept
700 return !v
.has_value();
703 template <typename T
>
704 constexpr bool operator>=(const optional
<T
> &v
, nullopt_t
) noexcept
709 template <typename T
>
710 constexpr bool operator==(nullopt_t
, const optional
<T
> &v
) noexcept
712 return !v
.has_value();
715 template <typename T
>
716 constexpr bool operator!=(nullopt_t
, const optional
<T
> &v
) noexcept
718 return v
.has_value();
721 template <typename T
>
722 constexpr bool operator<(nullopt_t
, const optional
<T
> &v
) noexcept
724 return v
.has_value();
727 template <typename T
>
728 constexpr bool operator>(nullopt_t
, const optional
<T
> &v
) noexcept
733 template <typename T
>
734 constexpr bool operator<=(nullopt_t
, const optional
<T
> &v
) noexcept
739 template <typename T
>
740 constexpr bool operator>=(nullopt_t
, const optional
<T
> &v
) noexcept
742 return !v
.has_value();
745 template <typename T
, typename U
>
746 constexpr bool operator==(const optional
<T
> &l
, const U
&r
) noexcept(
747 noexcept(static_cast<bool>(std::declval
<const T
&>() == std::declval
<const U
&>())))
754 template <typename T
, typename U
>
755 constexpr bool operator==(const U
&l
, const optional
<T
> &r
) noexcept(
756 noexcept(static_cast<bool>(std::declval
<const U
&>() == std::declval
<const T
&>())))
763 template <typename T
, typename U
>
764 constexpr bool operator!=(const optional
<T
> &l
, const U
&r
) noexcept(
765 noexcept(static_cast<bool>(std::declval
<const T
&>() != std::declval
<const U
&>())))
772 template <typename T
, typename U
>
773 constexpr bool operator!=(const U
&l
, const optional
<T
> &r
) noexcept(
774 noexcept(static_cast<bool>(std::declval
<const U
&>() != std::declval
<const T
&>())))
781 template <typename T
, typename U
>
782 constexpr bool operator<(const optional
<T
> &l
, const U
&r
) noexcept(
783 noexcept(static_cast<bool>(std::declval
<const T
&>() < std::declval
<const U
&>())))
790 template <typename T
, typename U
>
791 constexpr bool operator<(const U
&l
, const optional
<T
> &r
) noexcept(
792 noexcept(static_cast<bool>(std::declval
<const U
&>() < std::declval
<const T
&>())))
799 template <typename T
, typename U
>
800 constexpr bool operator>(const optional
<T
> &l
, const U
&r
) noexcept(
801 noexcept(static_cast<bool>(std::declval
<const T
&>() > std::declval
<const U
&>())))
808 template <typename T
, typename U
>
809 constexpr bool operator>(const U
&l
, const optional
<T
> &r
) noexcept(
810 noexcept(static_cast<bool>(std::declval
<const U
&>() > std::declval
<const T
&>())))
817 template <typename T
, typename U
>
818 constexpr bool operator<=(const optional
<T
> &l
, const U
&r
) noexcept(
819 noexcept(static_cast<bool>(std::declval
<const T
&>() <= std::declval
<const U
&>())))
826 template <typename T
, typename U
>
827 constexpr bool operator<=(const U
&l
, const optional
<T
> &r
) noexcept(
828 noexcept(static_cast<bool>(std::declval
<const U
&>() <= std::declval
<const T
&>())))
835 template <typename T
, typename U
>
836 constexpr bool operator>=(const optional
<T
> &l
, const U
&r
) noexcept(
837 noexcept(static_cast<bool>(std::declval
<const T
&>() >= std::declval
<const U
&>())))
844 template <typename T
, typename U
>
845 constexpr bool operator>=(const U
&l
, const optional
<T
> &r
) noexcept(
846 noexcept(static_cast<bool>(std::declval
<const U
&>() >= std::declval
<const T
&>())))
853 template <typename T
>
854 constexpr optional
<typename
std::decay
<T
>::type
> make_optional(T
&&value
)
856 return optional
<typename
std::decay
<T
>::type
>(in_place
, std::forward
<T
>(value
));
859 template <typename T
, typename
... Args
>
860 constexpr optional
<T
> make_optional(Args
&&... args
)
862 return optional
<T
>(in_place
, std::forward
<T
>(args
)...);
865 template <typename T
, typename U
, typename
... Args
>
866 constexpr optional
<T
> make_optional(std::initializer_list
<U
> init_list
, Args
&&... args
)
868 return optional
<T
>(in_place
, init_list
, std::forward
<T
>(args
)...);
871 template <typename T
,
872 typename
= typename
std::enable_if
<std::is_move_constructible
<T
>::value
873 && is_swappable
<T
>::value
>::type
>
874 void swap(optional
<T
> &l
, optional
<T
> &r
) noexcept(noexcept(l
.swap(r
)))
881 template <typename T
, bool Is_Enabled
= std::is_default_constructible
<std::hash
<T
>>::value
>
884 constexpr std::size_t operator()(const optional
<T
> &value
) const
885 noexcept(noexcept(static_cast<std::size_t>(std::hash
<T
>()(std::declval
<const T
&>()))))
888 return std::hash
<T
>()(*value
);
893 template <typename T
>
894 struct optional_hash
<T
, false>
896 optional_hash() noexcept
= delete;
897 ~optional_hash() = delete;
898 optional_hash(const optional_hash
&) noexcept
= delete;
899 optional_hash
&operator=(const optional_hash
&) noexcept
= delete;
900 std::size_t operator()(const optional
<T
> &value
) const noexcept
= delete;
908 template <typename T
>
909 struct hash
<vulkan_cpu::util::optional
<T
>> : public vulkan_cpu::util::detail::optional_hash
<T
>
914 #endif /* UTIL_OPTIONAL_H_ */