mirror of
https://github.com/boostorg/utility.git
synced 2025-05-09 02:44:10 +00:00
Added boost::initialized<T> as was agreed at http://lists.boost.org/Archives/boost/2010/04/164916.php -- see #3472
[SVN r61883]
This commit is contained in:
parent
e3c982287a
commit
22743ee125
@ -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 @@ class value_initialized
|
||||
typename
|
||||
#endif
|
||||
remove_const<T>::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<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 @@ 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<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 @@ T const& get ( value_initialized<T> const& x )
|
||||
{
|
||||
return x.data() ;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T& get ( value_initialized<T>& x )
|
||||
{
|
||||
@ -138,7 +216,7 @@ class initialized_value_t
|
||||
|
||||
template <class T> operator T() const
|
||||
{
|
||||
return get( value_initialized<T>() );
|
||||
return initialized<T>().data();
|
||||
}
|
||||
};
|
||||
|
||||
@ -147,5 +225,8 @@ initialized_value_t const initialized_value = {} ;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
116
initialized_test.cpp
Normal file
116
initialized_test.cpp
Normal file
@ -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();
|
||||
}
|
33
initialized_test_fail1.cpp
Normal file
33
initialized_test_fail1.cpp
Normal file
@ -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;
|
||||
}
|
37
initialized_test_fail2.cpp
Normal file
37
initialized_test_fail2.cpp
Normal file
@ -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;
|
||||
}
|
@ -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 ]
|
||||
;
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
<ul>
|
||||
<li><a href="#val_init"><code>template class value_initialized<T></code></a></li>
|
||||
<li><a href="#initialized"><code>template class initialized<T></code></a></li>
|
||||
<li><a href="#initialized_value"><code>initialized_value</code></a></li>
|
||||
|
||||
</ul>
|
||||
@ -123,6 +124,12 @@ constructed by the following declaration:
|
||||
</pre>
|
||||
</p>
|
||||
<p>
|
||||
The template <a href="#initialized"><code>initialized</code></a>
|
||||
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 <a href="#initialized_value"><code>initialized_value</code></a>
|
||||
allows value-initializing a variable as follows:
|
||||
<pre>
|
||||
@ -340,6 +347,52 @@ the wrapped object is always performed with the <code>get()</code> idiom:</p>
|
||||
|
||||
<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 @@ Special thanks to Björn Karlsson who carefully edited and completed this do
|
||||
<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@hotmail.com">Fernando Cacciola</a>,
|
||||
@ -407,9 +463,9 @@ for Boost release version 1.35 (2008), offering a workaround to various compiler
|
||||
</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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user