$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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.