diff --git a/value_init.htm b/value_init.htm index 5c1b20e..5c50fd9 100644 --- a/value_init.htm +++ b/value_init.htm @@ -253,7 +253,33 @@ its internal data, prior to constructing the object that it contains.
template class value_initialized<T>
namespace boost {+
template<class T>
class value_initialized
{
public :
value_initialized() : x() {}
operator T&() const { return x ; }
T& data() const { return x ; }
void swap( value_initialized<T>& );
private :
unspecified x ;
} ;
template<class T>
T const& get ( value_initialized<T> const& x )
{
return x.data() ;
}
template<class T>
T& get ( value_initialized<T>& x )
{
return x.data() ;
}
} // namespace boost
namespace boost {
template<class T>
class value_initialized
{ +
public : +
value_initialized() : x() {} +
operator T const &() const { return x ; } +
operator T&() { return x ; } +
T const &data() const { return x ; } +
T& data() { return x ; } +
void swap( value_initialized<T>& ); +
+
private : +
unspecified x ; +
} ; +
+
template<class T> +
T const& get ( value_initialized<T> const& x ) +
{ +
return x.data() ; +
} +
+
template<class T> +
T& get ( value_initialized<T>& x ) +
{ +
return x.data() ; +
} +
+
} // namespace boost +
An object of this template class is a T
-wrapper convertible
to 'T&'
whose wrapped object (data member of type T
)
@@ -271,7 +297,8 @@ its internal data, prior to constructing the object that it contains.
T&
, the member function data()
, or the
non-member function get()
:
void watch(int);+
value_initialized<int> x;
watch(x) ; // operator T& used.
watch(x.data());
watch( get(x) ) // function get() used
void watch(int);
value_initialized<int> x; +
watch(x) ; // operator T& used.
watch(x.data());
watch( get(x) ) // function get() used
Both const
and non-const
objects can be wrapped.
Mutable objects can be modified directly from within the wrapper but constant
@@ -281,37 +308,34 @@ non-member function get()
:
swap
member function
as well as by calling boost::swap
.
-value_initialized<int> x ;+
static_cast<int&>(x) = 1 ; // OK
get(x) = 1 ; // OK
value_initialized<int const> y ;
static_cast<int&>(y) = 1 ; // ERROR: cannot cast to int&
static_cast<int const&>(y) = 1 ; // ERROR: cannot modify a const value
get(y) = 1 ; // ERROR: cannot modify a const value
value_initialized<int> x ;
static_cast<int&>(x) = 1 ; // OK
get(x) = 1 ; // OK +
value_initialized<int const> y ;
static_cast<int&>(y) = 1 ; // ERROR: cannot cast to int&
static_cast<int const&>(y) = 1 ; // ERROR: cannot modify a const value
get(y) = 1 ; // ERROR: cannot modify a const value
Both the conversion operator and the data()
member function
- are const
in order to allow access to the wrapped object
-from a constant wrapper:
The value_initialized
implementation of Boost version 1.38.0 and older
+allowed non-const access to the wrapped object, from a constant wrapper,
+both by its conversion operator and its data()
member function. For example:
void foo(int);+
value_initialized<int> const x ;
foo(x);
value_initialized<int> const x_c ;-
int& xr = x_c ; // OK, conversion to int& available even though x_c is itself const. +
xr = 2 ;
But notice that this conversion operator is to T&
although
- it is itself const
. As a consequence, if T
is
- a non-const
type, you can modify the wrapped object even from
- within a constant wrapper:
value_initialized<int> const x_c ;- -
int& xr = x_c ; // OK, conversion to int& available even though x_c is itself const.
xr = 2 ;
The reason for this obscure behavior is that some commonly used compilers - just don't accept the following valid code:
+The reason for this obscure behavior was that some compilers + didn't accept the following valid code:
struct X-
{
operator int&() ;
operator int const&() const ;
};
X x ;
(x == 1 ) ; // ERROR HERE!
These compilers complain about ambiguity between the conversion operators.
- This complaint is incorrect, but the only workaround that I know of is
- to provide only one of them, which leads to the obscure behavior just explained.
+
The current version of value_initialized
no longer has this obscure behavior.
+As compilers nowadays widely support overloading the conversion operator by having a const
and a non-const
version, we have decided to fix the issue accordingly. So the current version supports the idea of logical constness.
+
The obscure behavior of being able to modify a non-const
-wrapped object from within a constant wrapper can be avoided if access to
+wrapped object from within a constant wrapper (as was supported by previous
+versions of value_initialized
)
+can be avoided if access to
the wrapped object is always performed with the get()
idiom:
value_initialized<int> x ;@@ -383,9 +407,9 @@ for Boost release version 1.35 (2008), offering a workaround to various compiler
get(x) = 1 ; // OK
value_initialized<int const> cx ;
get(x) = 1 ; // ERROR: Cannot modify a const object
value_initialized<int> const x_c ;
get(x_c) = 1 ; // ERROR: Cannot modify a const object
value_initialized<int const> const cx_c ;
get(cx_c) = 1 ; // ERROR: Cannot modify a const object
Revised 28 August 2008
+Revised 20 February 2009
-© Copyright Fernando Cacciola, 2002, 2008.
+© Copyright Fernando Cacciola, 2002, 2009.
Distributed under the Boost Software License, Version 1.0. See www.boost.org/LICENSE_1_0.txt
diff --git a/value_init_test.cpp b/value_init_test.cpp index 63f324d..67ebad8 100644 --- a/value_init_test.cpp +++ b/value_init_test.cpp @@ -260,7 +260,7 @@ bool test ( T const& y, T const& z ) boost::value_initialized