|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r61883 - in trunk: boost/utility libs/utility libs/utility/test
From: nielsdekker_at_[hidden]
Date: 2010-05-09 16:51:26
Author: niels_dekker
Date: 2010-05-09 16:51:24 EDT (Sun, 09 May 2010)
New Revision: 61883
URL: http://svn.boost.org/trac/boost/changeset/61883
Log:
Added boost::initialized<T> as was agreed at http://lists.boost.org/Archives/boost/2010/04/164916.php -- see #3472
Added:
trunk/libs/utility/initialized_test.cpp (contents, props changed)
trunk/libs/utility/initialized_test_fail1.cpp (contents, props changed)
trunk/libs/utility/initialized_test_fail2.cpp (contents, props changed)
Text files modified:
trunk/boost/utility/value_init.hpp | 123 +++++++++++++++++++++++++++++++++------
trunk/libs/utility/test/Jamfile.v2 | 3
trunk/libs/utility/value_init.htm | 60 ++++++++++++++++++
3 files changed, 163 insertions(+), 23 deletions(-)
Modified: trunk/boost/utility/value_init.hpp
==============================================================================
--- trunk/boost/utility/value_init.hpp (original)
+++ trunk/boost/utility/value_init.hpp 2010-05-09 16:51:24 EDT (Sun, 09 May 2010)
@@ -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<T>, 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 <cstring>
#include <new>
+#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 T>
-class value_initialized
+class initialized
{
private :
struct wrapper
@@ -40,6 +50,18 @@
typename
#endif
remove_const<T>::type data;
+
+ wrapper()
+ :
+ data()
+ {
+ }
+
+ wrapper(T const & arg)
+ :
+ data(arg)
+ {
+ }
};
mutable
@@ -55,30 +77,26 @@
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<wrapper const &>(*(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<T>::value );
@@ -86,7 +104,7 @@
return *this;
}
- ~value_initialized()
+ ~initialized()
{
wrapper_address()->wrapper::~wrapper();
}
@@ -101,17 +119,76 @@
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<class T>
+T const& get ( initialized<T> const& x )
+{
+ return x.data() ;
+}
+
+template<class T>
+T& get ( initialized<T>& x )
+{
+ return x.data() ;
+}
+
+template<class T>
+void swap ( initialized<T> & lhs, initialized<T> & rhs )
+{
+ lhs.swap(rhs) ;
+}
+
+template<class T>
+class value_initialized
+{
+ private :
+
+ // initialized<T> does value-initialization by default.
+ initialized<T> 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<class T>
@@ -119,6 +196,7 @@
{
return x.data() ;
}
+
template<class T>
T& get ( value_initialized<T>& x )
{
@@ -138,7 +216,7 @@
template <class T> operator T() const
{
- return get( value_initialized<T>() );
+ return initialized<T>().data();
}
};
@@ -147,5 +225,8 @@
} // namespace boost
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
#endif
Added: trunk/libs/utility/initialized_test.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/utility/initialized_test.cpp 2010-05-09 16:51:24 EDT (Sun, 09 May 2010)
@@ -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<T>.
+//
+// 2 May 2010 (Created) Niels Dekker
+
+#include <boost/utility/value_init.hpp>
+#include <boost/detail/lightweight_test.hpp>
+
+#include <string>
+
+namespace
+{
+ // Typical use case for boost::initialized<T>: A generic class that
+ // holds a value of type T, which must be initialized by either
+ // value-initialization or direct-initialization.
+ template <class T> class key_value_pair
+ {
+ std::string m_key;
+ boost::initialized<T> 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 <class T>
+ 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<T> 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<T>("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<T>("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();
+}
Added: trunk/libs/utility/initialized_test_fail1.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/utility/initialized_test_fail1.cpp 2010-05-09 16:51:24 EDT (Sun, 09 May 2010)
@@ -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<T>. Must fail to compile.
+//
+// Initial: 2 May 2010
+
+#include <boost/utility/value_init.hpp>
+
+namespace
+{
+ void direct_initialize_from_int()
+ {
+ // Okay: initialized<T> supports direct-initialization from T.
+ boost::initialized<int> direct_initialized_int(1);
+ }
+
+ void copy_initialize_from_int()
+ {
+ // The following line should not compile, because initialized<T>
+ // was not intended to supports copy-initialization from T.
+ boost::initialized<int> copy_initialized_int = 1;
+ }
+}
+
+int main()
+{
+ // This should fail to compile, so there is no need to call any function.
+ return 0;
+}
Added: trunk/libs/utility/initialized_test_fail2.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/utility/initialized_test_fail2.cpp 2010-05-09 16:51:24 EDT (Sun, 09 May 2010)
@@ -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<T>. Must fail to compile.
+//
+// Initial: 2 May 2010
+
+#include <boost/utility/value_init.hpp>
+
+namespace
+{
+ void from_value_initialized_to_initialized()
+ {
+ boost::value_initialized<int> value_initialized_int;
+
+ // Okay: initialized<T> can be initialized by value_initialized<T>.
+ boost::initialized<int> initialized_int(value_initialized_int);
+ }
+
+ void from_initialized_to_value_initialized()
+ {
+ boost::initialized<int> initialized_int(13);
+
+ // The following line should not compile, because initialized<T>
+ // should not be convertible to value_initialized<T>.
+ boost::value_initialized<int> value_initialized_int(initialized_int);
+ }
+}
+
+int main()
+{
+ // This should fail to compile, so there is no need to call any function.
+ return 0;
+}
Modified: trunk/libs/utility/test/Jamfile.v2
==============================================================================
--- trunk/libs/utility/test/Jamfile.v2 (original)
+++ trunk/libs/utility/test/Jamfile.v2 2010-05-09 16:51:24 EDT (Sun, 09 May 2010)
@@ -32,9 +32,12 @@
[ 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 ]
;
Modified: trunk/libs/utility/value_init.htm
==============================================================================
--- trunk/libs/utility/value_init.htm (original)
+++ trunk/libs/utility/value_init.htm 2010-05-09 16:51:24 EDT (Sun, 09 May 2010)
@@ -33,6 +33,7 @@
<ul>
<li>template class value_initialized<T>
</li>
+ <li>template class initialized<T>
</li>
<li>initialized_value
</li>
</ul>
@@ -123,6 +124,12 @@
</pre>
</p>
<p>
+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.
+</p>
+<p>
The <code>const</code> object initialized_value
allows value-initializing a variable as follows:
<pre>
@@ -340,6 +347,52 @@
<pre>value_initialized<int> x ;<br>get(x) = 1 ; // OK<br><br>value_initialized<int const> cx ;<br>get(x) = 1 ; // ERROR: Cannot modify a const object<br><br>value_initialized<int> const x_c ;<br>get(x_c) = 1 ; // ERROR: Cannot modify a const object<br><br>value_initialized<int const> const cx_c ;<br>get(cx_c) = 1 ; // ERROR: Cannot modify a const object<br></pre>
+<h2><a name="initialized"><code>template class initialized<T></code></a></h2>
+
+<pre>namespace boost {<br><br>template<class T><br>class initialized<br>{
+<br> public :
+<br> initialized() : x() {}
+<br> explicit initialized(T const & arg) : x(arg) {}
+<br> operator T const &() const;
+<br> operator T&();
+<br> T const &data() const;
+<br> T& data();
+<br> void swap( value_initialized<T>& );
+<br>
+<br> private :
+<br> <i>unspecified</i> x ;
+<br>} ;
+<br>
+<br>template<class T>
+<br>T const& get ( initialized<T> const& x );
+<br>
+<br>template<class T>
+<br>T& get ( initialized<T>& x );
+<br>
+<br>} // namespace boost
+<br></pre>
+
+The template class <code>boost::initialized<T></code> supports both value-initialization
+and direct-initialization, so its interface is a superset of the interface
+of <code>value_initialized<T></code>: Its default-constructor
+value-initializes the wrapped object just like the default-constructor of
+<code>value_initialized<T></code>, but <code>boost::initialized<T></code>
+also offers an extra <code>explicit</code>
+constructor, which direct-initializes the wrapped object by the specified value.
+<p>
+
+<code>initialized<T></code> is especially useful when the wrapped
+object must be either value-initialized or direct-initialized, depending on
+runtime conditions. For example, <code>initialized<T></code> 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 <i>always</i> be value-initialized, <code>value_initialized<T></code>
+may be preferable. And if the object must always be
+direct-initialized, none of the two wrappers really needs to be used.
+</p>
+
+
<h2><a name="initialized_value"><code>initialized_value</code></a></h2>
<pre>
@@ -399,6 +452,9 @@
<p>value_initialized was reimplemented by Fernando Cacciola and Niels Dekker
for Boost release version 1.35 (2008), offering a workaround to various compiler issues.
</p>
+<p><code>boost::initialized</code> was very much inspired by feedback from Edward Diener and
+ Jeffrey Hellrung.
+ </p>
<p>initialized_value was written by Niels Dekker, and added to Boost release version 1.36 (2008).
</p>
<p>Developed by <a href="mailto:fernando_cacciola_at_[hidden]">Fernando Cacciola</a>,
@@ -407,9 +463,9 @@
</p>
<hr>
-<p>Revised 03 October 2009</p>
+<p>Revised 1 May 2010</p>
-<p>© Copyright Fernando Cacciola, 2002, 2009.</p>
+<p>© Copyright Fernando Cacciola, 2002 - 2010.</p>
<p>Distributed under the Boost Software License, Version 1.0. See
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a></p>
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk