#include <system_error>
#include <type_traits>
#include <new>
// #define USE_OUTCOME
// #define USE_ERROR
// BOOST_NOINLINE ---------------------------------------------//
// Macro to use in place of 'inline' to prevent a function to be inlined
#if !defined(BOOST_NOINLINE)
# if defined(_MSC_VER)
# define BOOST_NOINLINE __declspec(noinline)
# elif defined(__GNUC__) && __GNUC__ > 3
// Clang also defines __GNUC__ (as 4)
# if defined(__CUDACC__)
// nvcc doesn't always parse __noinline__,
// see: https://s...content-available-to-author-only...t.org/trac/boost/ticket/9392
# define BOOST_NOINLINE __attribute__ ((noinline))
# else
# define BOOST_NOINLINE __attribute__ ((__noinline__))
# endif
# else
# define BOOST_NOINLINE
# endif
#endif
#ifdef USE_OUTCOME
#include <boost/outcome/monad.hpp>
using namespace BOOST_OUTCOME_V1_NAMESPACE;
#else
class not_an_error_category_impl : public std::error_category
{
public:
virtual const char* name() const noexcept { return ""; }
virtual std::string message( int ev ) const { return std::string{}; }
virtual std::error_condition default_error_condition( int ev ) const noexcept {
return std::error_condition( ev, *this );
}
};
not_an_error_category_impl instance;
inline const std::error_category& not_an_error_category()
{
return instance;
}
template< typename T >
struct result {
typedef typename std::aligned_storage<sizeof( T ), alignof(T)>::type value_store;
value_store value;
std::error_code error;
result( const T& x ) {
error.assign( 0, not_an_error_category() );
new(&value) T( x );
}
result( T&& x ) {
error.assign( 0, not_an_error_category() );
new(&value) T( std::move( x ) );
}
result( std::error_code x ) : error( x ) {
}
~result() {
destroy<T>();
}
result( const result& rhs ) {
copy<T>( rhs );
}
result( result&& rhs ) {
move<T>( std::move( rhs ) );
}
explicit operator bool() const {
return (&error.category() == ¬_an_error_category());
}
T& get() {
return *reinterpret_cast<T*>(&value);
}
template< typename U >
typename std::enable_if<std::is_trivially_destructible<U>::value>::type destroy() {}
template< typename U >
typename std::enable_if<!std::is_trivially_destructible<U>::value>::type destroy() {
if ( *this ) {
get().~T();
}
}
template< typename U >
typename std::enable_if<std::is_trivially_copyable<U>::value>::type copy( const result<T>& rhs ) {
value = rhs.value;
error = rhs.error;
}
template< typename U >
typename std::enable_if<!std::is_trivially_copyable<U>::value>::type copy( const result<T>& rhs ) {
destroy<T>();
if ( rhs ) {
new(&value) T( rhs.value );
}
error = rhs.error;
}
template< typename U >
typename std::enable_if<std::is_trivially_move_constructible<U>::value>::type move( result<T>&& rhs ) {
value = rhs.value;
error = rhs.error;
}
template< typename U >
typename std::enable_if<!std::is_trivially_move_constructible<U>::value>::type move( result<T>&& rhs ) {
destroy<T>();
if ( rhs ) {
new(&value) T( std::move( rhs.value ) );
}
error = rhs.error;
}
};
#endif
BOOST_NOINLINE result<int> bar()
{
#ifdef USE_ERROR
return std::make_error_code( std::errc::bad_address );
#else
return 1;
#endif
}
int main()
{
result<int> _foo = bar();
int foo = 0;
if ( _foo ) {
foo = _foo.get();
}
return foo;
}