Skip to content
This repository has been archived by the owner on Apr 6, 2021. It is now read-only.

Commit

Permalink
Added exceptional class which is implicitly convertible to expected.
Browse files Browse the repository at this point in the history
The idea is to replace the exceptional_tag and rename it exceptional.

Added some overloads to then to unwrap implicitly expected<expected<T>>.

Added a get_exceptional function returning exceptionals<E>. Useful when
the expected is invalid and the result needs un implicit constructor
from the exceptional value.

Fixed some issues with comparaision of expected<void>.

Added safe_divide example, which could be used as a simple example of
the proposal.

Added jamfile on test directory.
  • Loading branch information
viboes committed Jan 2, 2014
1 parent e6d54f7 commit 79a5cfc
Show file tree
Hide file tree
Showing 4 changed files with 413 additions and 31 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ libs/expected/test/bin/*
libs/expected/.DS_Store

libs/expected/test/getInt.cpp

.project

libs/expected/test/cpp11/bin/*
195 changes: 164 additions & 31 deletions boost/expected/expected.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

// TODO: We'd need to check if std::is_default_constructible is there too.
#ifndef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS
#define BOOST_EXPECTED_USE_DEFAULT_CONSTRUCTOR
#define BOOST_EXPECTED_USE_DEFAULT_CONSTRUCTOR
#include <type_traits>
#endif

Expand All @@ -36,7 +36,7 @@

#define MAKE_BOOST_FWD_REF_ARG(z, count, unused) BOOST_PP_COMMA_IF(count) BOOST_FWD_REF(Arg##count) arg##count
#define MAKE_BOOST_FWD_PARAM(z, count, unused) BOOST_PP_COMMA_IF(count) boost::forward<Arg##count>(arg##count)
#endif
#endif

# define REQUIRES(...) typename ::boost::enable_if_c<__VA_ARGS__, void*>::type = 0
# define T_REQUIRES(...) typename = typename ::boost::enable_if_c<(__VA_ARGS__)>::type
Expand Down Expand Up @@ -132,12 +132,12 @@ struct expected_error_traits
{
return error_type(e);
}

static error_type catch_exception()
{
throw;
}

static void bad_access(const error_type &e)
{
throw Exception(e);
Expand All @@ -160,12 +160,12 @@ struct expected_traits<boost::exception_ptr>
{
return boost::copy_exception(e);
}

static error_type catch_exception()
{
return boost::current_exception();
}

static void bad_access(const error_type &e)
{
boost::rethrow_exception(e);
Expand All @@ -183,12 +183,12 @@ struct expected_traits<std::exception_ptr>
{
return std::make_exception_ptr(e);
}

static error_type catch_exception()
{
return std::current_exception();
}

static void bad_access(const error_type &e)
{
std::rethrow_exception(e);
Expand Down Expand Up @@ -332,19 +332,19 @@ struct trivial_expected_base

BOOST_CONSTEXPR trivial_expected_base()
BOOST_NOEXCEPT_IF(has_nothrow_default_constructor<value_type>::value)
: has_value(true), storage()
: has_value(true), storage()
{}

BOOST_CONSTEXPR trivial_expected_base(only_set_valid_t, bool has_value)
: has_value(has_value)
: has_value(has_value)
{}

BOOST_CONSTEXPR trivial_expected_base(const value_type& v)
: has_value(true), storage(v)
: has_value(true), storage(v)
{}

BOOST_CONSTEXPR trivial_expected_base(value_type&& v)
: has_value(true), storage(constexpr_move(v))
: has_value(true), storage(constexpr_move(v))
{}

BOOST_CONSTEXPR trivial_expected_base(exceptional_t, error_type const& e)
Expand Down Expand Up @@ -472,6 +472,46 @@ template <typename T, typename E>
} // namespace detail

template <typename ValueType, typename ErrorType=std::exception_ptr>
class expected;

template <typename ErrorType=std::exception_ptr>
struct exceptionals {
ErrorType error_;

exceptionals(ErrorType e):error_(e) {};
};

template <class E>
exceptionals<E> make_error(E ex)
{
return exceptionals<E>(ex);
}

template <>
struct exceptionals<std::exception_ptr> {
std::exception_ptr error_;
exceptionals(std::exception_ptr e) : error_(e) {}
template <class E> exceptionals(E e) : error_(std::make_exception_ptr(e)) {}
};

template <class E>
exceptionals<std::exception_ptr> make_exceptional(E&& ex) {
return exceptionals<std::exception_ptr>(std::forward<E>(ex));
}

exceptionals<std::exception_ptr> make_exceptional(std::exception_ptr ex)
{
return exceptionals<std::exception_ptr>(ex);
}



template <typename T>
struct is_expected : false_type {};
template <typename T, typename E>
struct is_expected<expected<T,E> > : true_type {};

template <typename ValueType, typename ErrorType>
class expected
: detail::expected_base<ValueType, ErrorType>
{
Expand Down Expand Up @@ -549,7 +589,7 @@ class expected
&& std::is_copy_constructible<error_type>::value)
)
BOOST_NOEXCEPT_IF(
has_nothrow_copy_constructor<value_type>::value &&
has_nothrow_copy_constructor<value_type>::value &&
has_nothrow_copy_constructor<error_type>::value
)
: base_type(detail::only_set_valid, rhs.valid())
Expand Down Expand Up @@ -594,12 +634,27 @@ class expected
: base_type(exceptional, e)
{}


// Requires typeid(e) == typeid(E)
template <class E>
template <class E>
expected(exceptional_t, E const& e)
: base_type(exceptional, traits_type::from_error(e))
{}

expected(exceptionals<error_type> const& e
, REQUIRES(std::is_copy_constructible<error_type>::value)
)
BOOST_NOEXCEPT_IF(
has_nothrow_copy_constructor<error_type>::value
)
: base_type(exceptional, e.error_)
{}

// template <class E>
// expected(exceptionals<error_type> const& e)
// : base_type(exceptional, traits_type::from_error(e.error_))
// {}

#if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES
template <class... Args
#if !defined BOOST_EXPECTED_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS
Expand Down Expand Up @@ -728,7 +783,7 @@ class expected
return valid();
}
#endif

value_type& value()
{
if (!valid()) traits_type::bad_access(contained_err());
Expand Down Expand Up @@ -770,6 +825,11 @@ class expected
{
return contained_err();
}
BOOST_CONSTEXPR exceptionals<error_type> get_exceptional() const BOOST_NOEXCEPT
{
return contained_err();
}


// Utilities

Expand Down Expand Up @@ -835,7 +895,7 @@ class expected
{
try
{
f(value);
f(value());
return result_type();
}
catch(...)
Expand All @@ -849,7 +909,9 @@ class expected
template <typename F>
expected<typename result_of<F(value_type)>::type, error_type>
then(BOOST_RV_REF(F) f,
REQUIRES(!boost::is_same<typename result_of<F(value_type)>::type, void>::value)) const
REQUIRES(!boost::is_same<typename result_of<F(value_type)>::type, void>::value
&& !boost::is_expected<typename result_of<F(value_type)>::type>::value
)) const
{
typedef expected<typename result_of<F(value_type)>::type, error_type> result_type;
if(valid())
Expand All @@ -863,11 +925,28 @@ class expected
return result_type(exceptional);
}
}
return result_type(exceptional, error());
return *this;
}

template <typename F>
this_type recover(BOOST_RV_REF(F) f,
typename result_of<F(value_type)>::type
then(BOOST_RV_REF(F) f,
REQUIRES(!boost::is_same<typename result_of<F(value_type)>::type, void>::value
&& boost::is_expected<typename result_of<F(value_type)>::type>::value
)
) const
{
typedef typename result_of<F(value_type)>::type result_type;
if(valid())
{
return f(value());
}
return *this;
}

template <typename F>
this_type
recover(BOOST_RV_REF(F) f,
REQUIRES(boost::is_same<typename result_of<F(error_type)>::type, value_type>::value)) const
{
if(!valid())
Expand All @@ -881,7 +960,7 @@ class expected
return this_type(exceptional);
}
}
return this_type(value());
return *this;
}

template <typename F>
Expand All @@ -890,17 +969,34 @@ class expected
{
if(!valid())
{
try
{
return f(error());
}
return this_type(value());
}

template <typename Ex, typename F>
this_type catch_exception(BOOST_RV_REF(F) f,
REQUIRES(
boost::is_same<typename result_of<F(Ex &)>::type, this_type>::value
)) const
{
if(!valid())
{
try {
std::rethrow_exception(error());
}
catch(...)
catch(Ex& e)
{
return this_type(exceptional);
return f(e);
}
catch (...)
{
return *this;
}
}
return this_type(value());
return *this;
}

};

template <typename ErrorType>
Expand Down Expand Up @@ -1003,6 +1099,20 @@ class expected<void, ErrorType>
: base_type(exceptional, traits_type::catch_exception())
{}

expected(exceptionals<error_type> const& e
, REQUIRES(std::is_copy_constructible<error_type>::value)

)
BOOST_NOEXCEPT_IF(
has_nothrow_copy_constructor<error_type>::value
)
: base_type(exceptional, e.error_)
{}
// template <class E>
// expected(exceptionals<E> const& e)
// : base_type(exceptional, traits_type::from_error(e.error_))
// {}

~expected() = default;

// Assignments
Expand Down Expand Up @@ -1075,6 +1185,10 @@ class expected<void, ErrorType>
{
return contained_err();
}
BOOST_CONSTEXPR exceptionals<error_type> get_exceptional() const BOOST_NOEXCEPT
{
return contained_err();
}

// Utilities

Expand Down Expand Up @@ -1166,6 +1280,17 @@ BOOST_CONSTEXPR bool operator==(const expected<T, E>& x, const expected<T, E>& y

}

template <class E>
BOOST_CONSTEXPR bool operator==(const expected<void, E>& x, const expected<void, E>& y)
{
return (x && y)
? true
: (!x && !y)
? x.error() == y.error()
: false;

}

template <class T, class E>
BOOST_CONSTEXPR bool operator!=(const expected<T, E>& x, const expected<T, E>& y)
{
Expand All @@ -1180,6 +1305,14 @@ BOOST_CONSTEXPR bool operator<(const expected<T, E>& x, const expected<T, E>& y)
: (y) ? false : x.error() < y.error();
}

template <class E>
BOOST_CONSTEXPR bool operator<(const expected<void, E>& x, const expected<void, E>& y)
{
return (x)
? (y) ? false : true
: (y) ? false : x.error() < y.error();
}

template <class T, class E>
BOOST_CONSTEXPR bool operator>(const expected<T, E>& x, const expected<T, E>& y)
{
Expand Down Expand Up @@ -1268,11 +1401,11 @@ make_expected_from_call(F funct
) BOOST_NOEXCEPT
{
typedef typename boost::result_of<F()>::type result_type;
try
try
{
return make_expected<result_type>(funct());
}
catch (...)
}
catch (...)
{
return make_expected_from_error<result_type>();
}
Expand All @@ -1284,12 +1417,12 @@ make_expected_from_call(F funct
, REQUIRES( boost::is_same<typename boost::result_of<F()>::type, void>::value)
) BOOST_NOEXCEPT
{
try
try
{
funct();
return expected<void>();
}
catch (...)
}
catch (...)
{
return make_expected_from_error<void>();
}
Expand Down
Loading

0 comments on commit 79a5cfc

Please sign in to comment.