diff --git a/include/boost/utility/value_init.hpp b/include/boost/utility/value_init.hpp
index 5aefac9..8392f70 100644
--- a/include/boost/utility/value_init.hpp
+++ b/include/boost/utility/value_init.hpp
@@ -9,6 +9,7 @@
// 23 May 2008 (Fixed operator= const issue, added initialized_value) Niels Dekker, Fernando Cacciola
// 21 Ago 2008 (Added swap) Niels Dekker, Fernando Cacciola
// 20 Feb 2009 (Fixed logical const-ness issues) Niels Dekker, Fernando Cacciola
+// 03 Apr 2010 (Added initialized, suggested by Jeffrey Hellrung, fixing #3472) Niels Dekker
//
#ifndef BOOST_UTILITY_VALUE_INIT_21AGO2002_HPP
#define BOOST_UTILITY_VALUE_INIT_21AGO2002_HPP
@@ -28,10 +29,19 @@
#include
#include
+#ifdef BOOST_MSVC
+#pragma warning(push)
+#if _MSC_VER >= 1310
+// It is safe to ignore the following warning from MSVC 7.1 or higher:
+// "warning C4351: new behavior: elements of array will be default initialized"
+#pragma warning(disable: 4351)
+#endif
+#endif
+
namespace boost {
template
-class value_initialized
+class initialized
{
private :
struct wrapper
@@ -40,6 +50,18 @@ class value_initialized
typename
#endif
remove_const::type data;
+
+ wrapper()
+ :
+ data()
+ {
+ }
+
+ wrapper(T const & arg)
+ :
+ data(arg)
+ {
+ }
};
mutable
@@ -55,30 +77,26 @@ class value_initialized
public :
- value_initialized()
+ initialized()
{
+ // Note: the following memset call will become conditional when ticket #3869 is fixed:
+ // https://svn.boost.org/trac/boost/ticket/3869 reported by Aleksey Gurtovoy.
std::memset(&x, 0, sizeof(x));
-#ifdef BOOST_MSVC
-#pragma warning(push)
-#if _MSC_VER >= 1310
-// When using MSVC 7.1 or higher, the following placement new expression may trigger warning C4345:
-// "behavior change: an object of POD type constructed with an initializer of the form ()
-// will be default-initialized". It is safe to ignore this warning when using value_initialized.
-#pragma warning(disable: 4345)
-#endif
-#endif
+
new (wrapper_address()) wrapper();
-#ifdef BOOST_MSVC
-#pragma warning(pop)
-#endif
}
- value_initialized(value_initialized const & arg)
+ initialized(initialized const & arg)
{
new (wrapper_address()) wrapper( static_cast(*(arg.wrapper_address())));
}
- value_initialized & operator=(value_initialized const & arg)
+ explicit initialized(T const & arg)
+ {
+ new (wrapper_address()) wrapper(arg);
+ }
+
+ initialized & operator=(initialized const & arg)
{
// Assignment is only allowed when T is non-const.
BOOST_STATIC_ASSERT( ! is_const::value );
@@ -86,7 +104,7 @@ class value_initialized
return *this;
}
- ~value_initialized()
+ ~initialized()
{
wrapper_address()->wrapper::~wrapper();
}
@@ -101,17 +119,76 @@ class value_initialized
return wrapper_address()->data;
}
- void swap(value_initialized & arg)
+ void swap(initialized & arg)
{
::boost::swap( this->data(), arg.data() );
}
- operator T const &() const { return this->data(); }
+ operator T const &() const
+ {
+ return wrapper_address()->data;
+ }
- operator T&() { return this->data(); }
+ operator T&()
+ {
+ return wrapper_address()->data;
+ }
} ;
+template
+T const& get ( initialized const& x )
+{
+ return x.data() ;
+}
+
+template
+T& get ( initialized& x )
+{
+ return x.data() ;
+}
+
+template
+void swap ( initialized & lhs, initialized & rhs )
+{
+ lhs.swap(rhs) ;
+}
+
+template
+class value_initialized
+{
+ private :
+
+ // initialized does value-initialization by default.
+ initialized m_data;
+
+ public :
+
+ T const & data() const
+ {
+ return m_data.data();
+ }
+
+ T& data()
+ {
+ return m_data.data();
+ }
+
+ void swap(value_initialized & arg)
+ {
+ m_data.swap(arg.m_data);
+ }
+
+ operator T const &() const
+ {
+ return m_data;
+ }
+
+ operator T&()
+ {
+ return m_data;
+ }
+} ;
template
@@ -119,6 +196,7 @@ T const& get ( value_initialized const& x )
{
return x.data() ;
}
+
template
T& get ( value_initialized& x )
{
@@ -138,7 +216,7 @@ class initialized_value_t
template operator T() const
{
- return get( value_initialized() );
+ return initialized().data();
}
};
@@ -147,5 +225,8 @@ initialized_value_t const initialized_value = {} ;
} // namespace boost
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
#endif
diff --git a/initialized_test.cpp b/initialized_test.cpp
new file mode 100644
index 0000000..9380957
--- /dev/null
+++ b/initialized_test.cpp
@@ -0,0 +1,116 @@
+// Copyright 2010, Niels Dekker.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+// Test program for boost::initialized.
+//
+// 2 May 2010 (Created) Niels Dekker
+
+#include
+#include
+
+#include
+
+namespace
+{
+ // Typical use case for boost::initialized: A generic class that
+ // holds a value of type T, which must be initialized by either
+ // value-initialization or direct-initialization.
+ template class key_value_pair
+ {
+ std::string m_key;
+ boost::initialized m_value;
+ public:
+
+ // Value-initializes the object held by m_value.
+ key_value_pair() { }
+
+ // Value-initializes the object held by m_value.
+ explicit key_value_pair(const std::string& key)
+ :
+ m_key(key)
+ {
+ }
+
+ // Direct-initializes the object held by m_value.
+ key_value_pair(const std::string& key, const T& value)
+ :
+ m_key(key), m_value(value)
+ {
+ }
+
+ const T& get_value() const
+ {
+ return m_value;
+ }
+ };
+
+
+ // Tells whether the argument is value-initialized.
+ bool is_value_initialized(const int& arg)
+ {
+ return arg == 0;
+ }
+
+
+ // Tells whether the argument is value-initialized.
+ bool is_value_initialized(const std::string& arg)
+ {
+ return arg.empty();
+ }
+
+ struct foo
+ {
+ int data;
+ };
+
+ bool operator==(const foo& lhs, const foo& rhs)
+ {
+ return lhs.data == rhs.data;
+ }
+
+
+ // Tells whether the argument is value-initialized.
+ bool is_value_initialized(const foo& arg)
+ {
+ return arg.data == 0;
+ }
+
+
+ template
+ void test_key_value_pair(const T& magic_value)
+ {
+ // The value component of a default key_value_pair must be value-initialized.
+ key_value_pair default_key_value_pair;
+ BOOST_TEST( is_value_initialized(default_key_value_pair.get_value() ) );
+
+ // The value component of a key_value_pair that only has its key explicitly specified
+ // must also be value-initialized.
+ BOOST_TEST( is_value_initialized(key_value_pair("key").get_value()) );
+
+ // However, the value component of the following key_value_pair must be
+ // "magic_value", as it must be direct-initialized.
+ BOOST_TEST( key_value_pair("key", magic_value).get_value() == magic_value );
+ }
+}
+
+
+// Tests boost::initialize for a fundamental type, a type with a
+// user-defined constructor, and a user-defined type without
+// a user-defined constructor.
+int main()
+{
+
+ const int magic_number = 42;
+ test_key_value_pair(magic_number);
+
+ const std::string magic_string = "magic value";
+ test_key_value_pair(magic_string);
+
+ const foo magic_foo = { 42 };
+ test_key_value_pair(magic_foo);
+
+ return boost::report_errors();
+}
diff --git a/initialized_test_fail1.cpp b/initialized_test_fail1.cpp
new file mode 100644
index 0000000..ffeecab
--- /dev/null
+++ b/initialized_test_fail1.cpp
@@ -0,0 +1,33 @@
+// Copyright 2010, Niels Dekker.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+// Test program for boost::initialized. Must fail to compile.
+//
+// Initial: 2 May 2010
+
+#include
+
+namespace
+{
+ void direct_initialize_from_int()
+ {
+ // Okay: initialized supports direct-initialization from T.
+ boost::initialized direct_initialized_int(1);
+ }
+
+ void copy_initialize_from_int()
+ {
+ // The following line should not compile, because initialized
+ // was not intended to supports copy-initialization from T.
+ boost::initialized copy_initialized_int = 1;
+ }
+}
+
+int main()
+{
+ // This should fail to compile, so there is no need to call any function.
+ return 0;
+}
diff --git a/initialized_test_fail2.cpp b/initialized_test_fail2.cpp
new file mode 100644
index 0000000..f3fbf39
--- /dev/null
+++ b/initialized_test_fail2.cpp
@@ -0,0 +1,37 @@
+// Copyright 2010, Niels Dekker.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+// Test program for boost::initialized. Must fail to compile.
+//
+// Initial: 2 May 2010
+
+#include
+
+namespace
+{
+ void from_value_initialized_to_initialized()
+ {
+ boost::value_initialized value_initialized_int;
+
+ // Okay: initialized can be initialized by value_initialized.
+ boost::initialized initialized_int(value_initialized_int);
+ }
+
+ void from_initialized_to_value_initialized()
+ {
+ boost::initialized initialized_int(13);
+
+ // The following line should not compile, because initialized
+ // should not be convertible to value_initialized.
+ boost::value_initialized value_initialized_int(initialized_int);
+ }
+}
+
+int main()
+{
+ // This should fail to compile, so there is no need to call any function.
+ return 0;
+}
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index 3111cad..78bdd7f 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -32,9 +32,12 @@ test-suite utility
[ compile result_of_test.cpp ]
[ run ../shared_iterator_test.cpp ]
[ run ../value_init_test.cpp ]
+ [ run ../initialized_test.cpp ]
[ compile-fail ../value_init_test_fail1.cpp ]
[ compile-fail ../value_init_test_fail2.cpp ]
[ compile-fail ../value_init_test_fail3.cpp ]
+ [ compile-fail ../initialized_test_fail1.cpp ]
+ [ compile-fail ../initialized_test_fail2.cpp ]
[ run ../verify_test.cpp ]
;
diff --git a/value_init.htm b/value_init.htm
index 57b2313..018f63b 100644
--- a/value_init.htm
+++ b/value_init.htm
@@ -33,6 +33,7 @@
@@ -123,6 +124,12 @@ constructed by the following declaration:
+The template initialized
+offers both value-initialization and direct-initialization.
+It is especially useful as a data member type, allowing the very same object
+to be either direct-initialized or value-initialized.
+
+
The const
object initialized_value
allows value-initializing a variable as follows:
@@ -340,6 +347,52 @@ the wrapped object is always performed with the get()
idiom:
value_initialized<int> x ;
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
+
+
+namespace boost {
template<class T>
class initialized
{
+
public :
+
initialized() : x() {}
+
explicit initialized(T const & arg) : x(arg) {}
+
operator T const &() const;
+
operator T&();
+
T const &data() const;
+
T& data();
+
void swap( value_initialized<T>& );
+
+
private :
+
unspecified x ;
+
} ;
+
+
template<class T>
+
T const& get ( initialized<T> const& x );
+
+
template<class T>
+
T& get ( initialized<T>& x );
+
+
} // namespace boost
+
+
+The template class boost::initialized<T>
supports both value-initialization
+and direct-initialization, so its interface is a superset of the interface
+of value_initialized<T>
: Its default-constructor
+value-initializes the wrapped object just like the default-constructor of
+value_initialized<T>
, but boost::initialized<T>
+also offers an extra explicit
+constructor, which direct-initializes the wrapped object by the specified value.
+
+
+initialized<T>
is especially useful when the wrapped
+object must be either value-initialized or direct-initialized, depending on
+runtime conditions. For example, initialized<T>
could
+hold the value of a data member that may be value-initialized by some
+constructors, and direct-initialized by others.
+On the other hand, if it is known beforehand that the
+object must always be value-initialized, value_initialized<T>
+may be preferable. And if the object must always be
+direct-initialized, none of the two wrappers really needs to be used.
+
+
+
@@ -399,6 +452,9 @@ Special thanks to Björn Karlsson who carefully edited and completed this do
value_initialized was reimplemented by Fernando Cacciola and Niels Dekker
for Boost release version 1.35 (2008), offering a workaround to various compiler issues.
+boost::initialized
was very much inspired by feedback from Edward Diener and
+ Jeffrey Hellrung.
+
initialized_value was written by Niels Dekker, and added to Boost release version 1.36 (2008).
Developed by Fernando Cacciola,
@@ -407,9 +463,9 @@ for Boost release version 1.35 (2008), offering a workaround to various compiler
-Revised 03 October 2009
+Revised 1 May 2010
-© Copyright Fernando Cacciola, 2002, 2009.
+© Copyright Fernando Cacciola, 2002 - 2010.
Distributed under the Boost Software License, Version 1.0. See
www.boost.org/LICENSE_1_0.txt