martinmoene/expected-lite

expected<bool, E> doesn't work correctly

vsuponev opened this issue · 1 comments

Move-constructor expected( U && value of expected calls
contained.construct_value( std::forward<U>( value ) );
which leads to
new(&m_value) value_type(std::forward<Args>(args)...);
which degrades to calling
new(&m_value) bool(std::forward<Args>(args)...);
in the case of E=bool.

This means that if the expected object passed as rvalue has a value of false, the bool operator will still return true as it only checks has_value().

A specialized version of storage_t seems to resolve this issue.
I may have provided more member functions than required, but this is a fast fix as an inspiration. Also, I do not think we need placement new in such a trivial case.

Upd.: No idea what gh does with code formatting here...

/// discriminated union to hold bool and 'error'.
template< typename E >
union storage_t<bool, E>
{
friend class expected<bool,E>;

private:
using error_type = E;

// no-op construction
storage_t() {}
~storage_t() {}

void construct_value(bool value)
{
    m_value = value;
}

void construct_value(const expected<bool,E> &value)
{
    m_value = value.value();
}

void construct_value(expected<bool,E> &&value)
{
    m_value = value.value();
}

void destruct_value() {}

void construct_error( error_type const & e )
{
    new( &m_error ) error_type( e );
}

void construct_error( error_type && e )
{
    new( &m_error ) error_type( std::move( e ) );
}

void destruct_error()
{
    m_error.~error_type();
}

constexpr bool const & value() const &
{
    return m_value;
}

bool & value() &
{
    return m_value;
}

constexpr bool const && value() const &&
{
    return std::move( m_value );
}

nsel_constexpr14 bool && value() &&
{
    return std::move( m_value );
}

bool const * value_ptr() const
{
    return &m_value;
}

bool * value_ptr()
{
    return &m_value;
}

error_type const & error() const
{
    return m_error;
}

error_type & error()
{
    return m_error;
}

private:
bool m_value;
error_type m_error;
};