diff --git a/expected.hpp b/expected.hpp index 7bc2508..002fd49 100644 --- a/expected.hpp +++ b/expected.hpp @@ -69,62 +69,6 @@ namespace tl { template class expected; -/// \exclude -namespace detail { -template -using enable_if_t = typename std::enable_if::type; -template using decay_t = typename std::decay::type; - -// std::conjunction from C++17 -template struct conjunction : std::true_type {}; -template struct conjunction : B {}; -template -struct conjunction - : std::conditional, B>::type {}; - -// Trait for checking if a type is a tl::expected -template struct is_expected_impl : std::false_type {}; -template -struct is_expected_impl> : std::true_type {}; -template using is_expected = is_expected_impl>; - -// std::invoke from C++17 -// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround -template >{}>, - int = 0> -constexpr auto invoke(Fn &&f, Args &&... args) noexcept( - noexcept(std::mem_fn(f)(std::forward(args)...))) - -> decltype(std::mem_fn(f)(std::forward(args)...)) { - return std::mem_fn(f)(std::forward(args)...); -} - -template >{}>> -constexpr auto invoke(Fn &&f, Args &&... args) noexcept( - noexcept(std::forward(f)(std::forward(args)...))) - -> decltype(std::forward(f)(std::forward(args)...)) { - return std::forward(f)(std::forward(args)...); -} - -// std::invoke_result from C++17 -template struct invoke_result_impl; - -template -struct invoke_result_impl< - F, decltype(invoke(std::declval(), std::declval()...), void()), - Us...> { - using type = decltype(invoke(std::declval(), std::declval()...)); -}; - -template -using invoke_result = invoke_result_impl; - -template -using invoke_result_t = typename invoke_result::type; - -} // namespace detail - #ifndef TL_IN_PLACE_MONOSTATE_DEFINED #define TL_IN_PLACE_MONOSTATE_DEFINED /// \brief Used to represent an expected with no data @@ -211,6 +155,82 @@ struct unexpect_t { /// \brief A tag to tell expected to construct the unexpected value static constexpr unexpect_t unexpect{}; +/// \exclude +namespace detail { +template +using enable_if_t = typename std::enable_if::type; +template using decay_t = typename std::decay::type; + +// std::conjunction from C++17 +template struct conjunction : std::true_type {}; +template struct conjunction : B {}; +template +struct conjunction + : std::conditional, B>::type {}; + +// Trait for checking if a type is a tl::expected +template struct is_expected_impl : std::false_type {}; +template +struct is_expected_impl> : std::true_type {}; +template using is_expected = is_expected_impl>; + +// std::invoke from C++17 +// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround +template >{}>, + int = 0> +constexpr auto invoke(Fn &&f, Args &&... args) noexcept( + noexcept(std::mem_fn(f)(std::forward(args)...))) + -> decltype(std::mem_fn(f)(std::forward(args)...)) { + return std::mem_fn(f)(std::forward(args)...); +} + +template >{}>> +constexpr auto invoke(Fn &&f, Args &&... args) noexcept( + noexcept(std::forward(f)(std::forward(args)...))) + -> decltype(std::forward(f)(std::forward(args)...)) { + return std::forward(f)(std::forward(args)...); +} + +// std::invoke_result from C++17 +template struct invoke_result_impl; + +template +struct invoke_result_impl< + F, decltype(invoke(std::declval(), std::declval()...), void()), + Us...> { + using type = decltype(invoke(std::declval(), std::declval()...)); +}; + +template +using invoke_result = invoke_result_impl; + +template +using invoke_result_t = typename invoke_result::type; + +template +using enable_forward_value = detail::enable_if_t< + std::is_constructible::value && + !std::is_same, in_place_t>::value && + !std::is_same, detail::decay_t>::value && + !std::is_same, detail::decay_t>::value>; + +template +using enable_from_other = detail::enable_if_t< + std::is_constructible::value && + std::is_constructible::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value>; + +} // namespace detail + /// \exclude namespace detail { // Implements the storage of the values, and ensures that the destructor is @@ -1240,11 +1260,12 @@ public: : impl_base(unexpect, il, std::forward(args)...), ctor_base(detail::default_constructor_tag{}) {} - // TODO SFINAE - template ::value && - std::is_convertible::value)> * = - nullptr> + template < + class U, class G, + detail::enable_if_t::value && + std::is_convertible::value)> * = + nullptr, + detail::enable_from_other * = nullptr> explicit TL_EXPECTED_11_CONSTEXPR expected(const expected &rhs) : ctor_base(detail::default_constructor_tag{}) { if (rhs.has_value()) { @@ -1254,12 +1275,13 @@ public: } } - // TODO SFINAE /// \exclude - template ::value && - std::is_convertible::value)> * = - nullptr> + template < + class U, class G, + detail::enable_if_t<(std::is_convertible::value && + std::is_convertible::value)> * = + nullptr, + detail::enable_from_other * = nullptr> TL_EXPECTED_11_CONSTEXPR expected(const expected &rhs) : ctor_base(detail::default_constructor_tag{}) { if (rhs.has_value()) { @@ -1269,11 +1291,11 @@ public: } } - // TODO SFINAE template < class U, class G, detail::enable_if_t::value && - std::is_convertible::value)> * = nullptr> + std::is_convertible::value)> * = nullptr, + detail::enable_from_other * = nullptr> explicit TL_EXPECTED_11_CONSTEXPR expected(expected &&rhs) : ctor_base(detail::default_constructor_tag{}) { if (rhs.has_value()) { @@ -1283,12 +1305,12 @@ public: } } - // TODO SFINAE /// \exclude template < class U, class G, detail::enable_if_t<(std::is_convertible::value && - std::is_convertible::value)> * = nullptr> + std::is_convertible::value)> * = nullptr, + detail::enable_from_other * = nullptr> TL_EXPECTED_11_CONSTEXPR expected(expected &&rhs) : ctor_base(detail::default_constructor_tag{}) { if (rhs.has_value()) { @@ -1298,15 +1320,17 @@ public: } } - // TODO SFINAE - template ::value> * = nullptr> + template < + class U = T, + detail::enable_if_t::value> * = nullptr, + detail::enable_forward_value * = nullptr> explicit constexpr expected(U &&v) : expected(in_place, std::forward(v)) {} - // TODO SFINAE /// \exclude - template ::value> * = nullptr> + template < + class U = T, + detail::enable_if_t::value> * = nullptr, + detail::enable_forward_value * = nullptr> constexpr expected(U &&v) : expected(in_place, std::forward(v)) {} template < @@ -1619,7 +1643,7 @@ constexpr auto map_error_impl(Exp &&exp, F &&f) -> ret_t { template (), *std::declval())), - detail::enable_if_t::value> * = nullptr> + detail::enable_if_t::value> * = nullptr> constexpr detail::decay_t or_else_impl(Exp &&exp, F &&f) { if (exp.has_value()) { return std::forward(exp); @@ -1631,7 +1655,7 @@ constexpr detail::decay_t or_else_impl(Exp &&exp, F &&f) { template (), *std::declval())), - detail::enable_if_t::value> * = nullptr> + detail::enable_if_t::value> * = nullptr> detail::decay_t or_else_impl(Exp &&exp, F &&f) { if (exp.has_value()) { return std::forward(exp);