Boost logo

Boost :

From: Gennadiy E. Rozental (rogeeff_at_[hidden])
Date: 2001-08-30 14:22:32


Hi, Fernando

I spend some time overlooking this discussion and realized that what
really bother me is not the extern semantic. I agree with you that
providing an ability to the user to write s == value and *s == value
is not very good idea. It's confusing and error prone. So external
semantic should be pointer-like. BUT the implementation should be
value-based not pointer based, to eliminate dereferensing. Here what
I did. Compiled and tested on MSVC and sun workshop

#ifndef OPTIONAL_HPP
#define OPTIONAL_HPP

#include <boost/config.hpp>
#ifdef _DEBUG
#include <cassert>
#include <typeinfo.h>
#endif

namespace boost {

// Models a variable which has an associated 'm_initialized' state.
// A default constructed instance of optional<T> is uninitialized.

#ifdef _DEBUG

class UninitAccessAssertHandler {
public:
    operator()( std::string const& ) { assert( false ); }
};

class UninitAccessThrowHandler {
public:
    operator()( std::string const& message ) {
        throw std::logic_error( message );
    }
};

#endif

template<typename T
#ifdef _DEBUG
, class UninitAccessHandler = common_layer::UninitAccessAssertHandler
#endif
>
class optional;

namespace detail {

template<typename T>
class value_proxy {
public:
    // Constructor
    explicit value_proxy( optional<T>& opt ) : m_opt( opt ) {}

    // Value access
    operator T const&() const { return m_opt.value(); }
    template<typename U>
    optional<T> const& operator=( U const& arg ) const {
        m_opt.assign( arg );
        
        return m_opt;
    }

    // Comparison operators
#ifdef BOOST_MSVC
        template<typename U>
#else
        template<typename U, typename T>
#endif
    friend bool operator==( U const& lhs, value_proxy<T> const& rhs)
    { return (T const&)rhs == rhs; }
#ifdef BOOST_MSVC
    template<typename U>
#else
    template<typename U, typename T>
#endif
    friend bool operator!=( U const& lhs, value_proxy<T> const& rhs )
    { return (T const&)rhs != rhs; }

    template<typename U>
    bool operator==( U const& rhs ) const {
       return rhs == m_opt.value();
    }
    template<typename U>
    bool operator!=( U const& rhs ) const {
       return rhs != m_opt.value();
    }
    
private:
    optional<T>& m_opt;
};

} // namespace detail

template<typename T
#ifdef _DEBUG
, class UninitAccessHandler = common_layer::UninitAccessAssertHandler
#endif
>
class optional {
public :
    typedef T value_type;

    // Constructors does not allow convertion from type T. Use
*optional<T> = value; instead
    optional()
    : m_initialized( false ) {}
    optional( optional const& rhs )
    : m_v( rhs.m_v ), m_initialized(rhs.m_initialized) {}

    // Assignment operators
    template<class U>
    optional& operator=( optional<U> const& rhs ) {
        if( rhs.m_initialized )
           assign<U>( rhs.m_v );
        m_initialized = rhs.m_initialized;

        return *this;
    }

    // Value assign
    template<class U>
    void assign( U const& v ) {
        try {
            m_v = v;
            m_initialized = true;
        }
        catch( ... ) {
            m_initialized = false;
            throw;
        }
    }
        
    // Value access
    T const& value() const { return value_helper(); }
    T& value { return value_helper(); }
    T const& operator*() { return value_helper(); }
    detail::value_proxy<T> operator*() {
        return detail::value_proxy<T>( *this );
    }

    // operator arrow
    T const* operator->() const { return &(value_helper()); }
    T* operator->() { return &(value_helper()); }

    // Is initialized checks
    bool initialized() const { return m_initialized; }
    bool operator!() const { return !initialized(); }
    operator bool() const { return initialized(); }

private:
    T& value_helper() {
#ifdef _DEBUG
        if( !m_initialized ) {
            UninitAccessHandler()( std::string("Dereferencing
uninitialized ") + typeid(*this).name() );
        }
#endif
        return m_v;
    }
    // Data members
    T m_v;
    bool m_initialized;
};

} // namespace common_layer

#endif // OPTIONAL_HPP

Regards,

Gennadiy.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk