|
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