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
+

template class initialized<T>

+ +
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. +

+ +

initialized_value

@@ -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