forked from boostorg/utility
Transcribe documentation to quickbook
This commit is contained in:
1 parent
05e0d1688d
commit
703a4bf752
29 files changed
+4401
-6197
No files matched your search
@@ -0,0 +1,74 @@
|
||||
[/
|
||||
/ Copyright (c) 2012 Marshall Clow
|
||||
/ Copyright (c) 2021, Alan Freitas
|
||||
/ 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)
|
||||
/]
|
||||
|
||||
[/===============]
|
||||
[#sec:BOOST_BINARY]
|
||||
[section Binary Integer Literals]
|
||||
[/===============]
|
||||
|
||||
[heading Introduction]
|
||||
|
||||
The macro `BOOST_BINARY` is used for the representation of binary
|
||||
literals. It takes as an argument a binary number arranged as an
|
||||
arbitrary amount of 1s and 0s in groupings of length 1 to 8, with
|
||||
groups separated by spaces. The macro serves as a replacement for
|
||||
[@https://en.cppreference.com/w/cpp/language/integer_literal binary integer literals],
|
||||
adopted in C++14.
|
||||
|
||||
The type of the literal yielded is determined by the same rules as
|
||||
those of [@https://en.cppreference.com/w/cpp/language/integer_literal hex and octal literals].
|
||||
By implementation, this macro expands directly to an octal literal during preprocessing, so
|
||||
there is no overhead at runtime and the result is usable in any place that an octal literal
|
||||
would be.
|
||||
|
||||
In order to directly support binary literals with suffixes,
|
||||
additional macros of the form `BOOST_BINARY_XXX` are also
|
||||
provided, where `XXX` is a standard integer suffix in all capital
|
||||
letters.
|
||||
|
||||
In addition, LL and ULL suffixes may be used for representing
|
||||
`long long` and `unsigned long long` types in compilers which provide
|
||||
them as an extension.
|
||||
|
||||
The `BOOST_BINARY` family of macros resides in the header
|
||||
[@../../../include/boost/utility/binary.hpp <boost/utility/binary.hpp>].
|
||||
|
||||
[heading Example]
|
||||
|
||||
```
|
||||
void foo( int );
|
||||
|
||||
void foo( unsigned long );
|
||||
|
||||
void bar()
|
||||
{
|
||||
int value1 = BOOST_BINARY( 100 111000 01 1 110 );
|
||||
|
||||
unsigned long value2 = BOOST_BINARY_UL( 100 001 ); // unsigned long
|
||||
|
||||
long long value3 = BOOST_BINARY_LL( 11 000 ); // long long if supported
|
||||
|
||||
__assert__( BOOST_BINARY( 10010 )
|
||||
& BOOST_BINARY( 11000 )
|
||||
== BOOST_BINARY( 10000 )
|
||||
);
|
||||
|
||||
foo( BOOST_BINARY( 1010 ) ); // calls the first foo
|
||||
|
||||
foo( BOOST_BINARY_LU( 1010 ) ); // calls the second foo
|
||||
}
|
||||
```
|
||||
|
||||
[heading Acknowledgments]
|
||||
|
||||
Contributed by Matt Calabrese.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
+153
-151
@@ -1,5 +1,6 @@
|
||||
[/
|
||||
Copyright 2001, 2003, 2004, 2012 Daryle Walker.
|
||||
Copyright (c) 2021, Alan Freitas
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
|
||||
@@ -7,48 +8,43 @@
|
||||
or copy at http://boost.org/LICENSE_1_0.txt
|
||||
]
|
||||
|
||||
[article Base_From_Member
|
||||
[quickbook 1.5]
|
||||
[authors [Walker, Daryle]]
|
||||
[copyright 2001, 2003, 2004, 2012 Daryle Walker]
|
||||
[license
|
||||
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])
|
||||
]
|
||||
]
|
||||
[section:base_from_member Base from Member]
|
||||
[block'''<?dbhtml stop-chunking?>''']
|
||||
|
||||
[section Rationale]
|
||||
[heading Introduction]
|
||||
|
||||
The class templates __base_from_member__ support the base-from-member idiom.
|
||||
When developing a class, sometimes a base class needs to be initialized
|
||||
with a member of the current class. As a na\u00EFve example:
|
||||
|
||||
#include <streambuf> /* for std::streambuf */
|
||||
#include <ostream> /* for std::ostream */
|
||||
```
|
||||
#include <streambuf> /* for std::streambuf */
|
||||
#include <ostream> /* for std::ostream */
|
||||
|
||||
class fdoutbuf
|
||||
: public std::streambuf
|
||||
{
|
||||
public:
|
||||
explicit fdoutbuf( int fd );
|
||||
//...
|
||||
};
|
||||
class fdoutbuf
|
||||
: public __std_streambuf__
|
||||
{
|
||||
public:
|
||||
explicit fdoutbuf( int fd );
|
||||
//...
|
||||
};
|
||||
|
||||
class fdostream
|
||||
: public std::ostream
|
||||
{
|
||||
protected:
|
||||
fdoutbuf buf;
|
||||
public:
|
||||
explicit fdostream( int fd )
|
||||
: buf( fd ), std::ostream( &buf ) {}
|
||||
//...
|
||||
};
|
||||
class fdostream
|
||||
: public __std_ostream__
|
||||
{
|
||||
protected:
|
||||
fdoutbuf buf;
|
||||
public:
|
||||
explicit fdostream( int fd )
|
||||
: buf( fd ), __std_ostream__( &buf ) {}
|
||||
//...
|
||||
};
|
||||
```
|
||||
|
||||
This is undefined because C++'s initialization order mandates that the base
|
||||
class is initialized before the member it uses. [@http://www.moocat.org R.
|
||||
Samuel Klatchko] developed a way around this by using the initialization
|
||||
order in his favor. Base classes are intialized in order of declaration, so
|
||||
order in his favor. Base classes are initialized in order of declaration, so
|
||||
moving the desired member to another base class, that is initialized before
|
||||
the desired base class, can ensure proper initialization.
|
||||
|
||||
@@ -58,7 +54,7 @@ A custom base class can be made for this idiom:
|
||||
#include <ostream> /* for std::ostream */
|
||||
|
||||
class fdoutbuf
|
||||
: public std::streambuf
|
||||
: public __std_streambuf__
|
||||
{
|
||||
public:
|
||||
explicit fdoutbuf( int fd );
|
||||
@@ -75,10 +71,10 @@ A custom base class can be made for this idiom:
|
||||
|
||||
class fdostream
|
||||
: private fdostream_pbase
|
||||
, public std::ostream
|
||||
, public __std_ostream__
|
||||
{
|
||||
typedef fdostream_pbase pbase_type;
|
||||
typedef std::ostream base_type;
|
||||
typedef __std_ostream__ base_type;
|
||||
|
||||
public:
|
||||
explicit fdostream( int fd )
|
||||
@@ -104,9 +100,8 @@ parameter, an integer, that exists solely to provide type differentiation.
|
||||
This parameter has a default value so a single use of a particular member
|
||||
type does not need to concern itself with the integer.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Synopsis]
|
||||
[heading Synopsis]
|
||||
|
||||
#include <type_traits> /* exposition only */
|
||||
|
||||
@@ -115,41 +110,41 @@ type does not need to concern itself with the integer.
|
||||
#endif
|
||||
|
||||
template < typename MemberType, int UniqueID = 0 >
|
||||
class boost::base_from_member
|
||||
class __boost_base_from_member__
|
||||
{
|
||||
protected:
|
||||
MemberType member;
|
||||
|
||||
#if ``['C++11 is in use]``
|
||||
template< typename ...T >
|
||||
explicit constexpr base_from_member( T&& ...x )
|
||||
noexcept( std::is_nothrow_constructible<MemberType, T...>::value );
|
||||
explicit constexpr __base_from_member__( T&& ...x )
|
||||
noexcept( __std_is_nothrow_constructible__<MemberType, T...>::value );
|
||||
#else
|
||||
base_from_member();
|
||||
__base_from_member__();
|
||||
|
||||
template< typename T1 >
|
||||
explicit base_from_member( T1 x1 );
|
||||
explicit __base_from_member__( T1 x1 );
|
||||
|
||||
template< typename T1, typename T2 >
|
||||
base_from_member( T1 x1, T2 x2 );
|
||||
__base_from_member__( T1 x1, T2 x2 );
|
||||
|
||||
//...
|
||||
|
||||
template< typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8, typename T9,
|
||||
typename T10 >
|
||||
base_from_member( T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, T6 x6, T7 x7,
|
||||
__base_from_member__( T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, T6 x6, T7 x7,
|
||||
T8 x8, T9 x9, T10 x10 );
|
||||
#endif
|
||||
};
|
||||
|
||||
template < typename MemberType, int UniqueID >
|
||||
class base_from_member<MemberType&, UniqueID>
|
||||
class __base_from_member__<MemberType&, UniqueID>
|
||||
{
|
||||
protected:
|
||||
MemberType& member;
|
||||
|
||||
explicit constexpr base_from_member( MemberType& x )
|
||||
explicit constexpr __base_from_member__( MemberType& x )
|
||||
noexcept;
|
||||
};
|
||||
|
||||
@@ -158,21 +153,21 @@ the type of the based-member. It has a last template parameter `UniqueID`,
|
||||
that is an `int`, to differentiate between multiple base classes that use
|
||||
the same based-member type. The last template parameter has a default value
|
||||
of zero if it is omitted. The class template has a protected data member
|
||||
called `member` that the derived class can use for later base classes (or
|
||||
itself).
|
||||
called `member` that the derived class can use for later base classes or
|
||||
itself.
|
||||
|
||||
If the appropriate features of C++11 are present, there will be a single
|
||||
constructor template. It implements ['perfect forwarding] to the best
|
||||
constructor call of `member` (if any). The constructor template is marked
|
||||
constructor call of `member` if any. The constructor template is marked
|
||||
both `constexpr` and `explicit`. The former will be ignored if the
|
||||
corresponding inner constructor call (of `member`) does not have the marker.
|
||||
corresponding inner constructor call of `member` does not have the marker.
|
||||
The latter binds the other way; always taking effect, even when the inner
|
||||
constructor call does not have the marker. The constructor template
|
||||
propagates the `noexcept` status of the inner constructor call. (The
|
||||
propagates the `noexcept` status of the inner constructor call. The
|
||||
constructor template has a trailing parameter with a default value that
|
||||
disables the template when its signature is too close to the signatures of
|
||||
the automatically-defined non-template copy- and/or move-constructors of
|
||||
`base_from_member`.)
|
||||
__base_from_member__.
|
||||
|
||||
On earlier-standard compilers, there is a default constructor and several
|
||||
constructor member templates. These constructor templates can take as many
|
||||
@@ -195,150 +190,157 @@ maintain the same maximum size. (Example code would be a class that uses
|
||||
this class template as a base class for a member with a flexible set of
|
||||
constructors.) This constant is ignored when C++11 features are present.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Usage]
|
||||
[heading Basic Usage]
|
||||
|
||||
With the starting example, the `fdoutbuf` sub-object needs to be
|
||||
encapsulated in a base class that is inheirited before `std::ostream`.
|
||||
encapsulated in a base class that is inherited before `__std_ostream__`.
|
||||
|
||||
#include <boost/utility/base_from_member.hpp>
|
||||
```
|
||||
#include <boost/utility/base_from_member.hpp>
|
||||
|
||||
#include <streambuf> // for std::streambuf
|
||||
#include <ostream> // for std::ostream
|
||||
#include <streambuf> // for std::streambuf
|
||||
#include <ostream> // for __std_ostream__
|
||||
|
||||
class fdoutbuf
|
||||
: public std::streambuf
|
||||
{
|
||||
public:
|
||||
explicit fdoutbuf( int fd );
|
||||
//...
|
||||
};
|
||||
class fdoutbuf
|
||||
: public __std_streambuf__
|
||||
{
|
||||
public:
|
||||
explicit fdoutbuf( int fd );
|
||||
//...
|
||||
};
|
||||
|
||||
class fdostream
|
||||
: private boost::base_from_member<fdoutbuf>
|
||||
, public std::ostream
|
||||
{
|
||||
// Helper typedef's
|
||||
typedef boost::base_from_member<fdoutbuf> pbase_type;
|
||||
typedef std::ostream base_type;
|
||||
class fdostream
|
||||
: private __boost_base_from_member__<fdoutbuf>
|
||||
, public __std_ostream__
|
||||
{
|
||||
// Helper typedef's
|
||||
typedef __boost_base_from_member__<fdoutbuf> pbase_type;
|
||||
typedef __std_ostream__ base_type;
|
||||
|
||||
public:
|
||||
explicit fdostream( int fd )
|
||||
: pbase_type( fd ), base_type( &member ){}
|
||||
//...
|
||||
};
|
||||
public:
|
||||
explicit fdostream( int fd )
|
||||
: pbase_type( fd ), base_type( &member ){}
|
||||
//...
|
||||
};
|
||||
```
|
||||
|
||||
The base-from-member idiom is an implementation detail, so it should not
|
||||
be visible to the clients (or any derived classes) of `fdostream`. Due to
|
||||
the initialization order, the `fdoutbuf` sub-object will get initialized
|
||||
before the `std::ostream` sub-object does, making the former sub-object
|
||||
before the `__std_ostream__` sub-object does, making the former sub-object
|
||||
safe to use in the latter sub-object's construction. Since the `fdoutbuf`
|
||||
sub-object of the final type is the only sub-object with the name `member`
|
||||
that name can be used unqualified within the final class.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Example]
|
||||
[heading Multiple Sub-Objects]
|
||||
|
||||
The base-from-member class templates should commonly involve only one
|
||||
base-from-member sub-object, usually for attaching a stream-buffer to an
|
||||
I/O stream. The next example demonstrates how to use multiple
|
||||
base-from-member sub-objects and the resulting qualification issues.
|
||||
|
||||
#include <boost/utility/base_from_member.hpp>
|
||||
```
|
||||
#include <boost/utility/base_from_member.hpp>
|
||||
|
||||
#include <cstddef> /* for NULL */
|
||||
#include <cstddef> /* for NULL */
|
||||
|
||||
struct an_int
|
||||
{
|
||||
int y;
|
||||
struct an_int
|
||||
{
|
||||
int y;
|
||||
|
||||
an_int( float yf );
|
||||
};
|
||||
an_int( float yf );
|
||||
};
|
||||
|
||||
class switcher
|
||||
{
|
||||
public:
|
||||
switcher();
|
||||
switcher( double, int * );
|
||||
//...
|
||||
};
|
||||
class switcher
|
||||
{
|
||||
public:
|
||||
switcher();
|
||||
switcher( double, int * );
|
||||
//...
|
||||
};
|
||||
|
||||
class flow_regulator
|
||||
{
|
||||
public:
|
||||
flow_regulator( switcher &, switcher & );
|
||||
//...
|
||||
};
|
||||
class flow_regulator
|
||||
{
|
||||
public:
|
||||
flow_regulator( switcher &, switcher & );
|
||||
//...
|
||||
};
|
||||
|
||||
template < unsigned Size >
|
||||
class fan
|
||||
{
|
||||
public:
|
||||
explicit fan( switcher );
|
||||
//...
|
||||
};
|
||||
template < unsigned Size >
|
||||
class fan
|
||||
{
|
||||
public:
|
||||
explicit fan( switcher );
|
||||
//...
|
||||
};
|
||||
|
||||
class system
|
||||
: private boost::base_from_member<an_int>
|
||||
, private boost::base_from_member<switcher>
|
||||
, private boost::base_from_member<switcher, 1>
|
||||
, private boost::base_from_member<switcher, 2>
|
||||
, protected flow_regulator
|
||||
, public fan<6>
|
||||
{
|
||||
// Helper typedef's
|
||||
typedef boost::base_from_member<an_int> pbase0_type;
|
||||
typedef boost::base_from_member<switcher> pbase1_type;
|
||||
typedef boost::base_from_member<switcher, 1> pbase2_type;
|
||||
typedef boost::base_from_member<switcher, 2> pbase3_type;
|
||||
class system
|
||||
: private __boost_base_from_member__<an_int>
|
||||
, private __boost_base_from_member__<switcher>
|
||||
, private __boost_base_from_member__<switcher, 1>
|
||||
, private __boost_base_from_member__<switcher, 2>
|
||||
, protected flow_regulator
|
||||
, public fan<6>
|
||||
{
|
||||
// Helper typedef's
|
||||
typedef __boost_base_from_member__<an_int> pbase0_type;
|
||||
typedef __boost_base_from_member__<switcher> pbase1_type;
|
||||
typedef __boost_base_from_member__<switcher, 1> pbase2_type;
|
||||
typedef __boost_base_from_member__<switcher, 2> pbase3_type;
|
||||
|
||||
typedef flow_regulator base1_type;
|
||||
typedef fan<6> base2_type;
|
||||
typedef flow_regulator base1_type;
|
||||
typedef fan<6> base2_type;
|
||||
|
||||
public:
|
||||
system( double x );
|
||||
//...
|
||||
};
|
||||
public:
|
||||
system( double x );
|
||||
//...
|
||||
};
|
||||
|
||||
system::system( double x )
|
||||
: pbase0_type( 0.2 )
|
||||
, pbase1_type()
|
||||
, pbase2_type( -16, &this->pbase0_type::member.y )
|
||||
, pbase3_type( x, static_cast<int *>(NULL) )
|
||||
, base1_type( pbase3_type::member, pbase1_type::member )
|
||||
, base2_type( pbase2_type::member )
|
||||
{
|
||||
//...
|
||||
}
|
||||
system::system( double x )
|
||||
: pbase0_type( 0.2 )
|
||||
, pbase1_type()
|
||||
, pbase2_type( -16, &this->pbase0_type::member.y )
|
||||
, pbase3_type( x, static_cast<int *>(NULL) )
|
||||
, base1_type( pbase3_type::member, pbase1_type::member )
|
||||
, base2_type( pbase2_type::member )
|
||||
{
|
||||
//...
|
||||
}
|
||||
```
|
||||
|
||||
The final class has multiple sub-objects with the name `member`, so any
|
||||
use of that name needs qualification by a name of the appropriate base
|
||||
type. (Using `typedef`s ease mentioning the base types.) However, the fix
|
||||
introduces a new problem when a pointer is needed. Using the address
|
||||
operator with a sub-object qualified with its class's name results in a
|
||||
pointer-to-member (here, having a type of `an_int boost::base_from_member<
|
||||
an_int, 0> :: *`) instead of a pointer to the member (having a type of
|
||||
`an_int *`). The new problem is fixed by qualifying the sub-object with
|
||||
`this->` and is needed just for pointers, and not for references or values.
|
||||
type. Using `typedef`s ease mentioning the base types.
|
||||
|
||||
However, the fix introduces a new problem when a pointer is needed. Using the
|
||||
address operator with a sub-object qualified with its class's name results in a
|
||||
pointer-to-member (here, having a type of `an_int __boost_base_from_member__<an_int, 0>:: *`)
|
||||
instead of a pointer to the member (having a type of `an_int *`).
|
||||
The new problem is fixed by qualifying the sub-object with `this->` and is needed
|
||||
just for pointers, and not for references or values.
|
||||
|
||||
There are some argument conversions in the initialization. The constructor
|
||||
argument for `pbase0_type` is converted from `double` to `float`. The first
|
||||
constructor argument for `pbase2_type` is converted from `int` to `double`.
|
||||
|
||||
The second constructor argument for `pbase3_type` is a special case of
|
||||
necessary conversion; all forms of the null-pointer literal in C++ (except
|
||||
`nullptr` from C++11) also look like compile-time integral expressions, so
|
||||
C++ always interprets such code as an integer when it has overloads that can
|
||||
take either an integer or a pointer. The last conversion is necessary for the
|
||||
compiler to call a constructor form with the exact pointer type used in
|
||||
`switcher`'s constructor. (If C++11's `nullptr` is used, it still needs a
|
||||
conversion if multiple pointer types can be accepted in a constructor call
|
||||
but `std::nullptr_t` cannot.)
|
||||
take either an integer or a pointer.
|
||||
|
||||
[endsect]
|
||||
The last conversion is necessary for the compiler to call a constructor form
|
||||
with the exact pointer type used in `switcher`'s constructor. (If C++11's
|
||||
__nullptr__ is used, it still needs a conversion if multiple pointer types can
|
||||
be accepted in a constructor call but `__std_nullptr_t__` cannot.)
|
||||
|
||||
[section Acknowledgments]
|
||||
[heading Acknowledgments]
|
||||
|
||||
Author: Walker, Daryle
|
||||
|
||||
Copyright 2001, 2003, 2004, 2012 Daryle Walker
|
||||
|
||||
* [@http://www.boost.org/people/ed_brey.htm Ed Brey] suggested some interface
|
||||
changes.
|
||||
@@ -353,10 +355,10 @@ the idiom of how to use a class member for initializing a base class.
|
||||
|
||||
* Jonathan Turkanis supplied an implementation of generating the constructor
|
||||
templates that can be controlled and automated with macros. The
|
||||
implementation uses the [@../../../preprocessor/index.html Preprocessor library].
|
||||
implementation uses the [@boost:/doc/html/preprocessor/index.html Preprocessor library].
|
||||
|
||||
* [@http://www.boost.org/people/daryle_walker.html">Daryle Walker] started the
|
||||
library. Contributed the test file [@../../test/base_from_member_test.cpp
|
||||
library. Contributed the test file [@../../../test/base_from_member_test.cpp
|
||||
base_from_member_test.cpp].
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -0,0 +1,432 @@
|
||||
[/
|
||||
/ Copyright (c) 2012 Marshall Clow
|
||||
/ Copyright (c) 2021, Alan Freitas
|
||||
/
|
||||
/ 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)
|
||||
/]
|
||||
|
||||
[/===============]
|
||||
[section Call Traits]
|
||||
[/===============]
|
||||
|
||||
[heading Introduction]
|
||||
|
||||
All of the contents of [@../../../include/boost/call_traits.hpp `<boost/call_traits.hpp>`] are
|
||||
defined inside `namespace boost`.
|
||||
|
||||
The template class __call_traits_T__ encapsulates the
|
||||
"best" method to pass a parameter of some type `T` to or
|
||||
from a function, and consists of a collection of `typedef`s defined
|
||||
as in the table below. The purpose of __call_traits__ is to ensure
|
||||
that problems like [link sec:refs "references to references"]
|
||||
never occur, and that parameters are passed in the most efficient
|
||||
manner possible, as in the [link sec:examples examples]. In each
|
||||
case, if your existing practice is to use the type defined on the
|
||||
left, then replace it with the __call_traits__ defined type on the
|
||||
right.
|
||||
|
||||
Note that for compilers that do not support either partial
|
||||
specialization or member templates, no benefit will occur from
|
||||
using __call_traits__: the __call_traits__ defined types will always be
|
||||
the same as the existing practice in this case. In addition if
|
||||
only member templates and not partial template specialisation is
|
||||
support by the compiler (for example Visual C++ 6) then
|
||||
__call_traits__ cannot be used with array types, although it can still be
|
||||
used to solve the reference to reference problem.
|
||||
|
||||
[table __call_traits__ types
|
||||
[[Existing practice] [__call_traits__ equivalent] [Description] [Notes]]
|
||||
[
|
||||
[`T`
|
||||
|
||||
(return by value)
|
||||
]
|
||||
[
|
||||
__call_traits_T__`::value_type`
|
||||
]
|
||||
[
|
||||
Defines a type that represents the "value" of type `T`.
|
||||
|
||||
Use this for functions that return by value, or possibly for stored values of type `T`.
|
||||
]
|
||||
[2]
|
||||
]
|
||||
[
|
||||
[`T&`
|
||||
|
||||
(return value)
|
||||
]
|
||||
[
|
||||
__call_traits_T__`::reference`
|
||||
]
|
||||
[
|
||||
Defines a type that represents a reference to type `T`.
|
||||
|
||||
Use for functions that would normally return a `T&`.
|
||||
]
|
||||
[1]
|
||||
]
|
||||
[
|
||||
[`const T&`
|
||||
|
||||
(return value)
|
||||
]
|
||||
[
|
||||
__call_traits_T__`::const_reference`
|
||||
]
|
||||
[
|
||||
Defines a type that represents a constant reference to type `T`.
|
||||
|
||||
Use for functions that would normally return a `const T&`.
|
||||
]
|
||||
[1]
|
||||
]
|
||||
[
|
||||
[`const T&`
|
||||
|
||||
(function parameter)
|
||||
]
|
||||
[
|
||||
__call_traits_T__`::param_type`
|
||||
]
|
||||
[
|
||||
Defines a type that represents the "best" way to pass a parameter of type `T` to a function.
|
||||
]
|
||||
[1,3]
|
||||
]
|
||||
]
|
||||
|
||||
Notes:
|
||||
|
||||
# If `T` is already reference type, then __call_traits__ is
|
||||
defined such that [link sec:refs "references to references"]
|
||||
do not occur (requires partial specialization).
|
||||
# If `T` is an array type, then __call_traits__ defines `value_type`
|
||||
as a "constant pointer to type" rather than an
|
||||
"array of type" (requires partial specialization).
|
||||
Note that if you are using `value_type` as a stored value
|
||||
then this will result in storing a "constant pointer to
|
||||
an array" rather than the array itself. This may or may
|
||||
not be a good thing depending upon what you actually
|
||||
need (in other words take care!).
|
||||
# If `T` is a small built in type or a pointer, then `param_type`
|
||||
is defined as `T const`, instead of `T const&`. This can
|
||||
improve the ability of the compiler to optimize loops in
|
||||
the body of the function if they depend upon the passed
|
||||
parameter, the semantics of the passed parameter is
|
||||
otherwise unchanged (requires partial specialization).
|
||||
|
||||
|
||||
[heading Copy constructibility]
|
||||
|
||||
The following table defines which __call_traits__ types can always
|
||||
be copy-constructed from which other types:
|
||||
|
||||
[table Which __call_traits__ types can always be copy-constructed from which other types
|
||||
[[] [To `T`] [To `value_type`] [To `reference`] [To `const_reference`] [To `param_type`]]
|
||||
[[From `T`] [iff `T` is copy constructible] [iff `T` is copy constructible] [Yes] [Yes] [Yes]]
|
||||
[[From `value_type`] [iff `T` is copy constructible] [iff `T` is copy constructible] [No] [No] [Yes]]
|
||||
[[From `reference`] [iff `T` is copy constructible] [iff `T` is copy constructible] [Yes] [Yes] [Yes]]
|
||||
[[From `const_reference`] [iff `T` is copy constructible] [No] [No] [Yes] [Yes]]
|
||||
[[From `param_type`] [iff `T` is copy constructible] [iff `T` is copy constructible] [No] [No] [Yes]]
|
||||
]
|
||||
|
||||
If `T` is an assignable type the following assignments are possible:
|
||||
|
||||
[table Which __call_traits__ types are assignable from which other types
|
||||
[[] [To `T`] [To `value_type`] [To `reference`] [To `const_reference`] [To `param_type`]]
|
||||
[[From `T`] [Yes] [Yes] [-] [-] [-]]
|
||||
[[From `value_type`] [Yes] [Yes] [-] [-] [-]]
|
||||
[[From `reference`] [Yes] [Yes] [-] [-] [-]]
|
||||
[[From `const_reference`] [Yes] [Yes] [-] [-] [-]]
|
||||
[[From `param_type`] [Yes] [Yes] [-] [-] [-]]
|
||||
]
|
||||
|
||||
[#sec:examples]
|
||||
[heading Examples]
|
||||
|
||||
The following table shows the effect that __call_traits__ has on
|
||||
various types.
|
||||
|
||||
[table Examples of __call_traits__ types
|
||||
[[] [__call_traits__::`value_type`] [__call_traits__::`reference`] [__call_traits__::`const_reference`] [__call_traits__::`param_type`] [Applies to:]]
|
||||
[[From `my_class`] [`my_class`] [`my_class&`] [`const my_class&`] [`my_class const&`] [All user-defined types]]
|
||||
[[From `int`] [`int`] [`int&`] [`const int&`] [`int const`] [All small built-in types]]
|
||||
[[From `int*`] [`int*`] [`int*&`] [`int* const &`] [`int* const`] [All pointer types]]
|
||||
[[From `int&`] [`int&`] [`int&`] [`const int&`] [`int&`] [All reference types]]
|
||||
[[From `const int&`] [`const int&`] [`const int&`] [`const int&`] [`const int&`] [All constant reference types]]
|
||||
[[From `int[3]`] [`const int*`] [`int(&)[3]`] [`const int(&)[3]`] [`const int* const`] [All array types]]
|
||||
[[From `const int[3]`] [`const int*`] [`const int(&)[3]`] [`const int(&)[3]`] [`const int *const`] [All constant array types]]
|
||||
]
|
||||
|
||||
The table assumes the compiler supports partial
|
||||
specialization: if it does not then all types behave in
|
||||
the same way as the entry for "`my_class`", and
|
||||
__call_traits__ can not be used with reference or array types.
|
||||
|
||||
[heading Example 1:]
|
||||
|
||||
The following class is a trivial class that stores some type `T`
|
||||
by value (see the [@../../../test/call_traits_test.cpp `call_traits_test.cpp`]
|
||||
file). The aim is to illustrate how each of the available
|
||||
__call_traits__ `typedef`s may be used:
|
||||
|
||||
```
|
||||
template <class T>
|
||||
struct contained
|
||||
{
|
||||
// define our typedefs first, arrays are stored by value
|
||||
// so value_type is not the same as result_type:
|
||||
typedef typename __boost_call_traits__<T>::param_type param_type;
|
||||
typedef typename __boost_call_traits__<T>::reference reference;
|
||||
typedef typename __boost_call_traits__<T>::const_reference const_reference;
|
||||
typedef T value_type;
|
||||
typedef typename __boost_call_traits__<T>::value_type result_type;
|
||||
|
||||
// stored value:
|
||||
value_type v_;
|
||||
|
||||
// constructors:
|
||||
contained() {}
|
||||
contained(param_type p) : v_(p){}
|
||||
// return byval:
|
||||
result_type value() { return v_; }
|
||||
// return by_ref:
|
||||
reference get() { return v_; }
|
||||
const_reference const_get()const { return v_; }
|
||||
// pass value:
|
||||
void call(param_type p){}
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
[#sec:refs]
|
||||
[heading Example 2 (the reference to reference problem):]
|
||||
|
||||
Consider the definition of __std_binder1st__:
|
||||
|
||||
```
|
||||
template <class Operation>
|
||||
class binder1st :
|
||||
public __std_unary_function__<typename Operation::second_argument_type, typename Operation::result_type>
|
||||
{
|
||||
protected:
|
||||
Operation op;
|
||||
typename Operation::first_argument_type value;
|
||||
public:
|
||||
binder1st(const Operation& x, const typename Operation::first_argument_type& y);
|
||||
typename Operation::result_type operator()(const typename Operation::second_argument_type& x) const;
|
||||
};
|
||||
```
|
||||
|
||||
Now consider what happens in the relatively common case that
|
||||
the functor takes its second argument as a reference, that
|
||||
implies that `Operation::second_argument_type` is a
|
||||
reference type, `operator()` will now end up taking a
|
||||
reference to a reference as an argument, and that is not
|
||||
currently legal. The solution here is to modify `operator()`
|
||||
to use __call_traits__:
|
||||
|
||||
```
|
||||
typename Operation::result_type operator()(typename __call_traits__<typename Operation::second_argument_type>::param_type x) const;
|
||||
```
|
||||
|
||||
Now in the case that `Operation::second_argument_type`
|
||||
is a reference type, the argument is passed as a reference, and
|
||||
the no "reference to reference" occurs.
|
||||
|
||||
[#sec:example3]
|
||||
[heading Example 3 (the `make_pair` problem):]
|
||||
|
||||
If we pass the name of an array as one (or both) arguments to `__std_make_pair__`,
|
||||
then template argument deduction deduces the passed parameter as
|
||||
"const reference to array of `T`", this also applies to
|
||||
string literals (which are really array literals). Consequently
|
||||
instead of returning a pair of pointers, it tries to return a
|
||||
pair of arrays, and since an array type is not copy-constructible
|
||||
the code fails to compile. One solution is to explicitly cast the
|
||||
arguments to __std_make_pair__ to pointers, but __call_traits__ provides a
|
||||
better automatic solution that works safely even in generic code where the
|
||||
cast might do the wrong thing:
|
||||
|
||||
```
|
||||
template <class T1, class T2>
|
||||
__std_pair__<
|
||||
typename __boost_call_traits__<T1>::value_type,
|
||||
typename __boost_call_traits__<T2>::value_type>
|
||||
make_pair(const T1& t1, const T2& t2)
|
||||
{
|
||||
return __std_pair__<
|
||||
typename __boost_call_traits__<T1>::value_type,
|
||||
typename __boost_call_traits__<T2>::value_type>(t1, t2);
|
||||
}
|
||||
```
|
||||
|
||||
Here, the deduced argument types will be automatically
|
||||
degraded to pointers if the deduced types are arrays, similar
|
||||
situations occur in the standard binders and adapters: in
|
||||
principle in any function that "wraps" a temporary
|
||||
whose type is deduced. Note that the function arguments to
|
||||
__std_make_pair__ are not expressed in terms of __call_traits__: doing so
|
||||
would prevent template argument deduction from functioning.
|
||||
|
||||
[#sec:example4]
|
||||
[heading Example 4 (optimising fill):]
|
||||
|
||||
The __call_traits__ template will "optimize" the passing
|
||||
of a small built-in type as a function parameter. This mainly has
|
||||
an effect when the parameter is used within a loop body.
|
||||
|
||||
In the following example (see [@boost:/doc/html/type_traits/examples/fill_example.cpp `fill_example.cpp`]),
|
||||
a version of __std_fill__ is optimized in two ways: if the type
|
||||
passed is a single byte built-in type then __std_memset__ is used to
|
||||
effect the fill, otherwise a conventional C++ implementation is
|
||||
used, but with the passed parameter "optimized" using
|
||||
__call_traits__:
|
||||
|
||||
```
|
||||
template <bool opt>
|
||||
struct filler
|
||||
{
|
||||
template <typename I, typename T>
|
||||
static void do_fill(I first, I last, typename __boost_call_traits__<T>::param_type val)
|
||||
{
|
||||
while(first != last)
|
||||
{
|
||||
*first = val;
|
||||
++first;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct filler<true>
|
||||
{
|
||||
template <typename I, typename T>
|
||||
static void do_fill(I first, I last, T val)
|
||||
{
|
||||
__std_memset__(first, val, last-first);
|
||||
}
|
||||
};
|
||||
|
||||
template <class I, class T>
|
||||
inline void fill(I first, I last, const T& val)
|
||||
{
|
||||
enum { can_opt = boost::is_pointer<I>::value
|
||||
&& boost::is_arithmetic<T>::value
|
||||
&& (sizeof(T) == 1) };
|
||||
typedef filler<can_opt> filler_t;
|
||||
filler_t::template do_fill<I,T>(first, last, val);
|
||||
}
|
||||
```
|
||||
|
||||
The reason that this is "optimal" for small built-in types is that
|
||||
with the value passed as `T const` instead of `const T&` the compiler is
|
||||
able to tell both that the value is constant and that it is free
|
||||
of aliases. With this information the compiler is able to cache
|
||||
the passed value in a register, unroll the loop, or use
|
||||
explicitly parallel instructions: if any of these are supported.
|
||||
Exactly how much mileage you will get from this depends upon your
|
||||
compiler - we could really use some accurate benchmarking
|
||||
software as part of boost for cases like this.
|
||||
|
||||
Note that the function arguments to fill are not expressed in
|
||||
terms of __call_traits__: doing so would prevent template argument
|
||||
deduction from functioning. Instead fill acts as a "thin
|
||||
wrapper" that is there to perform template argument
|
||||
deduction, the compiler will optimise away the call to fill all
|
||||
together, replacing it with the call to `filler<>::do_fill`,
|
||||
which does use __call_traits__.
|
||||
|
||||
[heading Rationale]
|
||||
|
||||
The following notes are intended to briefly describe the
|
||||
rationale behind choices made in __call_traits__.
|
||||
|
||||
All user-defined types follow "existing practice" and need no comment.
|
||||
|
||||
Small built-in types, what the standard calls [@https://en.cppreference.com/w/cpp/language/types fundamental
|
||||
types], differ from existing practice only in the `param_type`
|
||||
`typedef`. In this case passing `T const` is compatible
|
||||
with existing practice, but may improve performance in some cases
|
||||
(see [link sec:example4 Example 4]). In any case this should never
|
||||
be any worse than existing practice.
|
||||
|
||||
Pointers follow the same rationale as small built-in types.
|
||||
|
||||
For reference types the rationale follows [link sec:refs Example 2]
|
||||
- references to references are not allowed, so the __call_traits__
|
||||
members must be defined such that these problems do
|
||||
not occur. There is a proposal to modify the language such that
|
||||
"a reference to a reference is a reference" (issue #106,
|
||||
submitted by Bjarne Stroustrup). __call_traits_T__`::value_type`
|
||||
and __call_traits_T__`::param_type` both provide the same effect
|
||||
as that proposal, without the need for a language change. In
|
||||
other words, it's a workaround.
|
||||
|
||||
For array types, a function that takes an array as an argument
|
||||
will degrade the array type to a pointer type: this means that
|
||||
the type of the actual parameter is different from its declared
|
||||
type, something that can cause endless problems in template code
|
||||
that relies on the declared type of a parameter.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
template <class T>
|
||||
struct A
|
||||
{
|
||||
void foo(T t);
|
||||
};
|
||||
```
|
||||
|
||||
In this case if we instantiate `A<int[2]>` then the declared type of
|
||||
the parameter passed to member function `foo` is `int[2]`, but its
|
||||
actual type is `const int*`. If we try to use the type `T` within the
|
||||
function body, then there is a strong likelihood that our code will not compile:
|
||||
|
||||
```
|
||||
template <class T>
|
||||
void A<T>::foo(T t)
|
||||
{
|
||||
T dup(t); // doesn't compile for case that T is an array.
|
||||
}
|
||||
```
|
||||
|
||||
By using __call_traits__ the degradation from array to pointer is
|
||||
explicit, and the type of the parameter is the same as it's
|
||||
declared type:
|
||||
|
||||
```
|
||||
template <class T>
|
||||
struct A
|
||||
{
|
||||
void foo(typename __call_traits__<T>::value_type t);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void A<T>::foo(typename __call_traits__<T>::value_type t)
|
||||
{
|
||||
typename __call_traits__<T>::value_type dup(t); // OK even if T is an array type.
|
||||
}
|
||||
```
|
||||
|
||||
For `value_type` (return by value), again only a pointer may be
|
||||
returned, not a copy of the whole array, and again __call_traits__
|
||||
makes the degradation explicit. The `value_type` member is useful
|
||||
whenever an array must be explicitly degraded to a pointer -
|
||||
[link sec:example3 Example 3] provides the test case.
|
||||
|
||||
Footnote: the array specialisation for __call_traits__ is the least
|
||||
well understood of all the __call_traits__ specialisations. If the given
|
||||
semantics cause specific problems for you, or does not solve a particular
|
||||
array-related problem, then I would be interested to hear about
|
||||
it. Most people though will probably never need to use this
|
||||
specialisation.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
+44
-55
@@ -1,5 +1,6 @@
|
||||
[/
|
||||
Copyright 2000 Beman Dawes & John Maddock.
|
||||
Copyright (c) 2021, Alan Freitas
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
|
||||
@@ -7,89 +8,77 @@
|
||||
or copy at http://boost.org/LICENSE_1_0.txt
|
||||
]
|
||||
|
||||
[article Compressed_Pair
|
||||
[quickbook 1.5]
|
||||
[authors [Cleary, Steve]]
|
||||
[authors [Dawes, Beman]]
|
||||
[authors [Hinnant, Howard]]
|
||||
[authors [Maddock, John]]
|
||||
[copyright 2000 Steve Cleary, Beman Dawes, Howard Hinnant & John Maddock]
|
||||
[license
|
||||
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])
|
||||
]
|
||||
]
|
||||
[section Compressed Pair]
|
||||
|
||||
[section Overview]
|
||||
[heading Introduction]
|
||||
|
||||
All of the contents of `<boost/compressed_pair.hpp>` are defined inside
|
||||
All of the contents of [@../../../include/boost/compressed_pair.hpp `<boost/compressed_pair.hpp>`] are defined inside
|
||||
`namespace boost`.
|
||||
|
||||
The class `compressed_pair` is very similar to `std::pair`, but if either of
|
||||
the template arguments are empty classes, then the ['empty base-class
|
||||
optimisation] is applied to compress the size of the pair.
|
||||
The class __compressed_pair__ is very similar to __std_pair__. However, if either of
|
||||
the template arguments are empty classes, then the
|
||||
[@https://en.cppreference.com/w/cpp/language/ebo ['empty base-class optimisation]]
|
||||
is applied to compress the size of the pair.
|
||||
|
||||
[endsect]
|
||||
[heading Synopsis]
|
||||
|
||||
[section Synopsis]
|
||||
```cpp
|
||||
template <class T1, class T2>
|
||||
class __compressed_pair__
|
||||
{
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename __call_traits__<first_type>::param_type first_param_type;
|
||||
typedef typename __call_traits__<second_type>::param_type second_param_type;
|
||||
typedef typename __call_traits__<first_type>::reference first_reference;
|
||||
typedef typename __call_traits__<second_type>::reference second_reference;
|
||||
typedef typename __call_traits__<first_type>::const_reference first_const_reference;
|
||||
typedef typename __call_traits__<second_type>::const_reference second_const_reference;
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair
|
||||
{
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
compressed_pair() : base() {}
|
||||
compressed_pair(first_param_type x, second_param_type y);
|
||||
explicit compressed_pair(first_param_type x);
|
||||
explicit compressed_pair(second_param_type y);
|
||||
|
||||
compressed_pair() : base() {}
|
||||
compressed_pair(first_param_type x, second_param_type y);
|
||||
explicit compressed_pair(first_param_type x);
|
||||
explicit compressed_pair(second_param_type y);
|
||||
compressed_pair& operator=(const compressed_pair&);
|
||||
|
||||
compressed_pair& operator=(const compressed_pair&);
|
||||
first_reference first();
|
||||
first_const_reference first() const;
|
||||
|
||||
first_reference first();
|
||||
first_const_reference first() const;
|
||||
second_reference second();
|
||||
second_const_reference second() const;
|
||||
|
||||
second_reference second();
|
||||
second_const_reference second() const;
|
||||
|
||||
void swap(compressed_pair& y);
|
||||
};
|
||||
void swap(compressed_pair& y);
|
||||
};
|
||||
```
|
||||
|
||||
The two members of the pair can be accessed using the member functions
|
||||
`first()` and `second()`. Note that not all member functions can be
|
||||
instantiated for all template parameter types. In particular
|
||||
`compressed_pair` can be instantiated for reference and array types,
|
||||
however in these cases the range of constructors that can be used are
|
||||
__compressed_pair__ can be instantiated for reference and array types,
|
||||
however in these cases the range of constructors that can be used is
|
||||
limited. If types `T1` and `T2` are the same type, then there is only
|
||||
one version of the single-argument constructor, and this constructor
|
||||
initialises both values in the pair to the passed value.
|
||||
|
||||
Note that if either member is a POD type, then that member is not
|
||||
zero-initialized by the `compressed_pair` default constructor: it's up
|
||||
to you to supply an initial value for these types if you want them to have
|
||||
Note that if either member is a [@https://en.cppreference.com/w/cpp/named_req/PODType POD]
|
||||
type, then that member is not zero-initialized by the __compressed_pair__ default constructor:
|
||||
it is up to you to supply an initial value for these types if you want them to have
|
||||
a default value.
|
||||
|
||||
Note that `compressed_pair` can not be instantiated if either of the
|
||||
Note that __compressed_pair__ can not be instantiated if either of the
|
||||
template arguments is a union type, unless there is compiler support for
|
||||
`boost::is_union`, or if `boost::is_union` is specialised for the union
|
||||
type.
|
||||
[@boost:/doc/html/type_traits/index.html `boost::is_union`], or
|
||||
if [@boost:/doc/html/type_traits/index.html `boost::is_union`] is
|
||||
specialised for the union type.
|
||||
|
||||
Finally, a word of caution for Visual C++ 6 users: if either argument is an
|
||||
empty type, then assigning to that member will produce memory corruption,
|
||||
unless the empty type has a "do nothing" assignment operator defined. This
|
||||
is due to a bug in the way VC6 generates implicit assignment operators.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Acknowledgments]
|
||||
[heading Acknowledgments]
|
||||
|
||||
Based on contributions by Steve Cleary, Beman Dawes, Howard Hinnant and
|
||||
John Maddock.
|
||||
|
||||
-114
@@ -1,114 +0,0 @@
|
||||
[/
|
||||
/ Copyright (c) 2008 Howard Hinnant
|
||||
/ Copyright (c) 2009-2012 Vicente J. Botet Escriba
|
||||
/
|
||||
/ 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)
|
||||
/]
|
||||
|
||||
[article Declval
|
||||
[quickbook 1.5]
|
||||
[authors [Hinnant, Howard]]
|
||||
[authors [Botet Escriba, Vicente J.]]
|
||||
[copyright 2008 Howard Hinnant]
|
||||
[copyright 2009-2012 Vicente J. Botet Escriba]
|
||||
[license
|
||||
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])
|
||||
]
|
||||
]
|
||||
|
||||
[/===============]
|
||||
[section Overview]
|
||||
[/===============]
|
||||
|
||||
The motivation for `declval` was introduced in [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2958.html#Value N2958:
|
||||
Moving Swap Forward]. Here follows a rewording of this chapter.
|
||||
|
||||
With the provision of decltype, late-specified return types, and default template-arguments for function templates a
|
||||
new generation of SFINAE patterns will emerge to at least partially compensate the lack of concepts on the C++0x timescale.
|
||||
Using this technique, it is sometimes necessary to obtain an object of a known type in a non-using context, e.g. given the declaration
|
||||
|
||||
template<class T>
|
||||
T&& declval(); // not used
|
||||
|
||||
as part of the function template declaration
|
||||
|
||||
template<class To, class From>
|
||||
decltype(static_cast<To>(declval<From>())) convert(From&&);
|
||||
|
||||
or as part of a class template definition
|
||||
|
||||
template<class> class result_of;
|
||||
|
||||
template<class Fn, class... ArgTypes>
|
||||
struct result_of<Fn(ArgTypes...)>
|
||||
{
|
||||
typedef decltype(declval<Fn>()(declval<ArgTypes>()...)) type;
|
||||
};
|
||||
|
||||
The role of the function template declval() is a transformation of a type T into a value without using or evaluating this function.
|
||||
The name is supposed to direct the reader's attention to the fact that the expression `declval<T>()` is an lvalue if and only if
|
||||
T is an lvalue-reference, otherwise an rvalue. To extend the domain of this function we can do a bit better by changing its declaration to
|
||||
|
||||
template<class T>
|
||||
typename std::add_rvalue_reference<T>::type declval(); // not used
|
||||
|
||||
which ensures that we can also use cv void as template parameter. The careful reader might have noticed that `declval()`
|
||||
already exists under the name create() as part of the definition of the semantics of the type trait is_convertible in the C++0x standard.
|
||||
|
||||
The provision of a new library component that allows the production of values in unevaluated expressions is considered
|
||||
important to realize constrained templates in C++0x where concepts are not available.
|
||||
This extremely light-weight function is expected to be part of the daily tool-box of the C++0x programmer.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[/=================]
|
||||
[section:reference Reference ]
|
||||
[/=================]
|
||||
|
||||
`#include <boost/utility/declval.hpp>`
|
||||
|
||||
namespace boost {
|
||||
|
||||
template <typename T>
|
||||
typename add_rvalue_reference<T>::type declval() noexcept; // as unevaluated operand
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
The library provides the function template declval to simplify the definition of expressions which occur as unevaluated operands.
|
||||
|
||||
template <typename T>
|
||||
typename add_rvalue_reference<T>::type declval();
|
||||
|
||||
[*Remarks:] If this function is used, the program is ill-formed.
|
||||
|
||||
[*Remarks:] The template parameter T of declval may be an incomplete type.
|
||||
|
||||
[*Example:]
|
||||
|
||||
template <class To, class From>
|
||||
decltype(static_cast<To>(declval<From>())) convert(From&&);
|
||||
|
||||
Declares a function template convert which only participates in overloading if the type From can be explicitly converted to type To.
|
||||
|
||||
[endsect]
|
||||
|
||||
[/===============]
|
||||
[section History]
|
||||
[/===============]
|
||||
|
||||
[heading boost 1.50]
|
||||
|
||||
Fixes:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6570 #6570] Adding noexcept to boost::declval.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
[/
|
||||
/ Copyright (c) 2012 Marshall Clow
|
||||
/ Copyright (c) 2021, Alan Freitas
|
||||
/
|
||||
/ 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)
|
||||
/]
|
||||
|
||||
[/===============]
|
||||
[#sec:in_place_factory]
|
||||
[section In-place Factory]
|
||||
[/===============]
|
||||
|
||||
[heading Introduction]
|
||||
|
||||
Suppose we have a class
|
||||
|
||||
```
|
||||
struct X
|
||||
{
|
||||
X ( int, _std__string_ ) ;
|
||||
};
|
||||
```
|
||||
|
||||
And a container for it which supports an empty state. That is, a container which can contain zero objects:
|
||||
|
||||
```
|
||||
struct C
|
||||
{
|
||||
C() : contained_(0) {}
|
||||
~C() { delete contained_ ; }
|
||||
X* contained_ ;
|
||||
};
|
||||
```
|
||||
|
||||
A container designed to support an empty state typically does not require the contained type to be
|
||||
__DefaultConstructible__, but it typically requires it to be __CopyConstructible__ as a mechanism to
|
||||
initialize the object to store:
|
||||
|
||||
```
|
||||
struct C
|
||||
{
|
||||
C() : contained_(0) {}
|
||||
C ( X const& v ) : contained_ ( new X(v) ) {}
|
||||
~C() { delete contained_ ; }
|
||||
X* contained_ ;
|
||||
};
|
||||
```
|
||||
|
||||
There is a subtle problem with this: since the mechanism used to initialize the stored object is copy construction,
|
||||
there must exist a previously constructed source object to copy from. This object is likely to be temporary and serve
|
||||
no purpose besides being the source:
|
||||
|
||||
```
|
||||
void foo()
|
||||
{
|
||||
// Temporary object created.
|
||||
C c( X(123,"hello") ) ;
|
||||
}
|
||||
```
|
||||
|
||||
A solution to this problem is to support direct construction of the contained
|
||||
object right in the container's storage.
|
||||
|
||||
In this scheme, the user supplies the arguments for the `X` constructor
|
||||
directly to the container:
|
||||
|
||||
```
|
||||
struct C
|
||||
{
|
||||
C() : contained_(0) {}
|
||||
C ( X const& v ) : contained_ ( new X(v) ) {}
|
||||
C ( int a0, std::string a1 ) : contained_ ( new X(a0,a1) ) {}
|
||||
~C() { delete contained_ ; }
|
||||
X* contained_ ;
|
||||
};
|
||||
```
|
||||
|
||||
```
|
||||
void foo()
|
||||
{
|
||||
// Wrapped object constructed in-place
|
||||
// No temporary created.
|
||||
C c(123,"hello");
|
||||
}
|
||||
```
|
||||
|
||||
Clearly, this solution does not scale well since the container must duplicate all the constructor overloads
|
||||
from the contained type, or at least all those which are to be supported directly in the container.
|
||||
|
||||
[heading Framework]
|
||||
|
||||
This library proposes a framework to allow some containers to directly construct contained objects in-place without requiring
|
||||
the entire set of constructor overloads from the contained type. It also allows the container to remove the __CopyConstructible__
|
||||
requirement from the contained type since objects can be directly constructed in-place without need of a copy.
|
||||
|
||||
The only requirement on the container is that it must provide proper storage. That is, the container should be
|
||||
correctly aligned and sized. Naturally, the container will typically support uninitialized storage to avoid the
|
||||
in-place construction to override a fully-constructed object, as this would defeat the purpose of in-place construction.
|
||||
|
||||
For this purpose, the framework provides two concepts called: InPlaceFactories and TypedInPlaceFactories.
|
||||
Helpers to declare these classes are declared in [@../../../include/boost/utility/in_place_factory.hpp `<boost/utility/in_place_factory.hpp>`]
|
||||
and [@../../../include/boost/utility/typed_in_place_factory.hpp `<boost/utility/typed_in_place_factory.hpp>`].
|
||||
|
||||
Essentially, these classes hold a sequence of actual parameters and a method to construct an object in place using these parameters.
|
||||
Each member of the family differs only in the number and type of the parameter list. The first family
|
||||
takes the type of the object to construct directly in method provided for that
|
||||
purpose, whereas the second family incorporates that type in the factory class
|
||||
itself. From the container point of view, using the framework amounts to calling the
|
||||
factory's method to contruct the object in place. From the user point of view, it amounts to creating
|
||||
the right factory object to hold the parameters and pass it to the container.
|
||||
|
||||
The following simplified example shows the basic idea. A complete example follows the formal specification of the framework:
|
||||
|
||||
```
|
||||
struct C
|
||||
{
|
||||
template <class InPlaceFactory>
|
||||
C ( InPlaceFactory const& aFactory )
|
||||
:
|
||||
contained_ ( uninitialized_storage() )
|
||||
{
|
||||
aFactory.template apply<X>(contained_);
|
||||
}
|
||||
|
||||
~C()
|
||||
{
|
||||
contained_ -> X::~X();
|
||||
delete[] contained_ ;
|
||||
}
|
||||
|
||||
char* uninitialized_storage() { return new char[sizeof(X)] ; }
|
||||
|
||||
char* contained_ ;
|
||||
};
|
||||
|
||||
void foo()
|
||||
{
|
||||
C c( in_place(123,"hello") ) ;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
[heading Specification]
|
||||
|
||||
The following is the first member of the family of `InPlaceFactory` classes, along with its corresponding helper template function.
|
||||
The rest of the family varies only in the number and type of template and constructor parameters.
|
||||
|
||||
|
||||
```
|
||||
namespace boost {
|
||||
|
||||
struct __in_place_factory_base__ {};
|
||||
|
||||
template<class A0>
|
||||
class in_place_factory : public __in_place_factory_base__
|
||||
{
|
||||
public:
|
||||
in_place_factory ( A0 const& a0 ) : m_a0(a0) {}
|
||||
|
||||
template< class T >
|
||||
void apply ( void* address ) const
|
||||
{
|
||||
new (address) T(m_a0);
|
||||
}
|
||||
|
||||
private:
|
||||
A0 const& m_a0 ;
|
||||
};
|
||||
|
||||
template<class A0>
|
||||
in_place_factory<A0> in_place ( A0 const& a0 )
|
||||
{
|
||||
return in_place_factory<A0>(a0);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Similarly, the following is the first member of the family of `typed_in_place_factory` classes, along with its corresponding
|
||||
helper template function. The rest of the family varies only in the number and type of template and constructor parameters.
|
||||
|
||||
```
|
||||
namespace boost {
|
||||
|
||||
struct __typed_in_place_factory_base__ {};
|
||||
|
||||
template<class T, class A0>
|
||||
class typed_in_place_factory : public __typed_in_place_factory_base__
|
||||
{
|
||||
public:
|
||||
typed_in_place_factory ( A0 const& a0 ) : m_a0(a0) {}
|
||||
|
||||
void apply ( void* address ) const
|
||||
{
|
||||
new (address) T(m_a0);
|
||||
}
|
||||
|
||||
private:
|
||||
A0 const& m_a0 ;
|
||||
};
|
||||
|
||||
template<class T, class A0>
|
||||
typed_in_place_factory<A0> in_place ( A0 const& a0 )
|
||||
{
|
||||
return typed_in_place_factory<T,A0>(a0);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, the `in_place_factory` and `typed_in_place_factory` template classes vary only in the way they specify
|
||||
the target type: in the first family, the type is given as a template argument to the apply member function while in the
|
||||
second it is given directly as part of the factory class.
|
||||
|
||||
When the container holds a unique non-polymorphic type, such as the case of [@boost:/doc/html/optional/index.html Boost.Optional],
|
||||
it knows the exact dynamic-type of the contained object and can pass it to the `apply()` method of a non-typed factory.
|
||||
In this case, end users can use an `in_place_factory` instance which can be constructed without the type of the object to construct.
|
||||
|
||||
However, if the container holds heterogeneous or polymorphic objects, such as the case of [@boost:/doc/html/variant/index.html Boost.Variant],
|
||||
the dynamic-type of the object to be constructed must be known by the factory. In this case, end users must use a `typed_in_place_factory`
|
||||
instead.
|
||||
|
||||
[heading Container-side Usage]
|
||||
|
||||
As shown in the introductory simplified example, the container class must contain methods that accept an instance of
|
||||
these factories and pass the object's storage to the factory's apply method.
|
||||
|
||||
However, the type of the factory class cannot be completely specified in the container class because that would
|
||||
defeat the whole purpose of the factories which is to allow the container to accept a variadic argument list
|
||||
for the constructor of its contained object.
|
||||
|
||||
The correct function overload must be based on the only distinctive and common
|
||||
characteristic of all the classes in each family: the base class.
|
||||
|
||||
Depending on the container class, you can use `enable_if` to generate the right overload, or use the following
|
||||
dispatch technique, which is used in the [@boost:/doc/html/optional/index.html Boost.Optional] class:
|
||||
|
||||
|
||||
```
|
||||
struct C
|
||||
{
|
||||
C() : contained_(0) {}
|
||||
C ( X const& v ) : contained_ ( new X(v) ) {}
|
||||
|
||||
template <class Expr>
|
||||
C ( Expr const& expr )
|
||||
:
|
||||
contained_ ( uninitialized_storage() )
|
||||
{
|
||||
construct(expr,&expr);
|
||||
}
|
||||
|
||||
~C() { delete contained_ ; }
|
||||
|
||||
template<class InPlaceFactory>
|
||||
void construct ( InPlaceFactory const& aFactory, boost::__in_place_factory_base__* )
|
||||
{
|
||||
aFactory.template apply<X>(contained_);
|
||||
}
|
||||
|
||||
template<class TypedInPlaceFactory>
|
||||
void construct ( TypedInPlaceFactory const& aFactory, boost::__typed_in_place_factory_base__* )
|
||||
{
|
||||
aFactory.apply(contained_);
|
||||
}
|
||||
|
||||
X* uninitialized_storage() { return static_cast<X*>(new char[sizeof(X)]) ; }
|
||||
|
||||
X* contained_ ;
|
||||
};
|
||||
```
|
||||
|
||||
[heading User-side Usage]
|
||||
|
||||
End users pass to the container an instance of a factory object holding the actual parameters needed to construct the
|
||||
contained object directly within the container. For this, the helper template function `in_place` is used.
|
||||
|
||||
The call `in_place(a0,a1,a2,...,an)` constructs a (non-typed) `in_place_factory` instance with the given argument list.
|
||||
|
||||
The call `in_place<T>(a0,a1,a2,...,an)` constructs a `typed_in_place_factory` instance with the given argument list for the
|
||||
type `T`.
|
||||
|
||||
```
|
||||
void foo()
|
||||
{
|
||||
C a( in_place(123, "hello") ) ; // in_place_factory passed
|
||||
C b( in_place<X>(456, "world") ) ; // typed_in_place_factory passed
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
[heading Acknowledgments]
|
||||
|
||||
Copyright Fernando Luis Cacciola Carballal, 2004
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
+1986
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,407 @@
|
||||
[/
|
||||
/ Copyright (c) 2012 Marshall Clow
|
||||
/ Copyright (c) 2021, Alan Freitas
|
||||
/
|
||||
/ 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)
|
||||
/]
|
||||
|
||||
[/===============]
|
||||
[section Result of]
|
||||
[/===============]
|
||||
|
||||
[heading Introduction]
|
||||
|
||||
The class template __result_of__ helps determine the type of a
|
||||
call expression. For example, given an lvalue `f` of type `F`
|
||||
and lvalues `t1`,`t2`, ..., `tN` of types `T1`, `T2`, ..., `TN`,
|
||||
respectively, the type __result_of__`<F(T1, T2, ..., TN)>::type` defines
|
||||
the result type of the expression `f(t1, t2, ...,tN)`.
|
||||
|
||||
This implementation permits the type `F` to be a function pointer,
|
||||
function reference, member function pointer, or class type. By default,
|
||||
N may be any value between 0 and 16. To change the upper limit, define
|
||||
the macro `BOOST_RESULT_OF_NUM_ARGS` to the maximum value for N. Class
|
||||
template __result_of__ resides in the header
|
||||
[@../../../include/boost/utility/result_of.hpp `<boost/utility/result_of.hpp>`].
|
||||
|
||||
If your compiler's support for __decltype__ is adequate, __result_of__
|
||||
automatically uses it to deduce the type of the call expression, in
|
||||
which case __result_of__`<F(T1, T2, ..., TN)>::type` names the type
|
||||
__decltype__`(boost::declval<F>()(boost::declval<T1>(),
|
||||
boost::declval<T2>(), ..., boost::declval<TN>()))`, as in the
|
||||
following example.
|
||||
|
||||
```
|
||||
struct functor {
|
||||
template<class T>
|
||||
T operator()(T x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
typedef __boost_result_of__<functor(int)>::type type; // type is int
|
||||
```
|
||||
|
||||
You can test whether __result_of__ is using __decltype__ by checking if
|
||||
the macro `BOOST_RESULT_OF_USE_DECLTYPE` is defined after
|
||||
including `result_of.hpp`. You can also force __result_of__ to use
|
||||
__decltype__ by defining `BOOST_RESULT_OF_USE_DECLTYPE` prior
|
||||
to including `result_of.hpp`.
|
||||
|
||||
If __decltype__ is not used, then automatic result type deduction of function
|
||||
objects is not possible. Instead, __result_of__ uses the following protocol
|
||||
to allow the programmer to specify a type. When `F` is a class type with a
|
||||
member type `result_type`, `result_of<F(T1, T2, ..., TN)>::type` is
|
||||
`F::result_type`. When `F` does not contain `result_type`,
|
||||
`result_of<F(T1, T2, ..., TN)>::type` is
|
||||
`F::result<F(T1, T2, ..., TN)>::type` when
|
||||
`N > 0` or `void` when `N = 0`.
|
||||
|
||||
Note that it is the responsibility of the programmer to ensure that
|
||||
function objects accurately advertise their result
|
||||
type via this protocol, as in the following example.
|
||||
|
||||
```
|
||||
struct functor {
|
||||
template <class> struct result;
|
||||
|
||||
template<class F, class T>
|
||||
struct result<F(T)> {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
T operator()(T x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
typedef __boost_result_of__<functor(int)>::type type; // type is int
|
||||
```
|
||||
|
||||
Since __decltype__ is a language feature standardized in C++11, if you are
|
||||
writing a function object to be used with __result_of__, for maximum
|
||||
portability, you might consider following the above protocol
|
||||
even if your compiler has proper __decltype__ support.
|
||||
|
||||
If you wish to continue to use the protocol on compilers that
|
||||
support __decltype__, there are two options:
|
||||
|
||||
* You can use __boost_tr1_result_of__, which is also defined in
|
||||
[@../../../boost/utility/result_of.hpp `<boost/utility/result_of.hpp>`].
|
||||
|
||||
* Alternatively, you can define the macro `BOOST_RESULT_OF_USE_TR1`,
|
||||
which causes __result_of__ to use the protocol described above instead
|
||||
of __decltype__. If you choose to follow the protocol, take care to
|
||||
ensure that the `result_type` and `result<>` members accurately
|
||||
represent the return type of `operator()` given a call expression.
|
||||
|
||||
Additionally, __boost_result_of__ provides a third mode of operation,
|
||||
which some users may find convenient. When
|
||||
`BOOST_RESULT_OF_USE_TR1_WITH_DECLTYPE_FALLBACK` is defined,
|
||||
__boost_result_of__ behaves as follows. If the function object has a member
|
||||
type `result_type` or member template `result<>`, then __boost_result_of__
|
||||
will use the TR1 protocol.
|
||||
|
||||
Otherwise, __boost_result_of__ will use __decltype__. Using TR1 with
|
||||
a __decltype__ fallback may workaround certain problems at the cost of portability.
|
||||
For example:
|
||||
|
||||
* Deficient compiler: If your code requires __boost_result_of__ to work
|
||||
with incomplete return types but your compiler's __decltype__ implementation
|
||||
does not support incomplete return types, then you can use the TR1 protocol
|
||||
as a workaround. Support for incomplete return types was added late in the
|
||||
C++11 standardization process
|
||||
(see [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3276.pdf N3276])
|
||||
and is not implemented by some compilers.
|
||||
|
||||
* Deficient legacy code: If your existing TR1 function object advertises a different type than
|
||||
the actual result type deduced by __decltype__, then using TR1 with a __decltype__ fallback
|
||||
will allow you to work with both your existing TR1 function objects and new C++11
|
||||
function object. This situation could occur if your legacy function objects
|
||||
misused the TR1 protocol. See the documentation on known [link sec:result_of_tr1_diff differences]
|
||||
between __boost_result_of__ and TR1.
|
||||
|
||||
* [#BOOST_NO_RESULT_OF] This implementation of __result_of__ requires class template
|
||||
partial specialization, the ability to parse function types properly, and support
|
||||
for SFINAE. If __result_of__ is not supported by your compiler, including the header
|
||||
[@../../../boost/utility/result_of.hpp `<boost/utility/result_of.hpp>`] will define
|
||||
the macro `BOOST_NO_RESULT_OF`.
|
||||
|
||||
For additional information about __result_of__, see the C++ Library
|
||||
Technical Report, [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf N1836],
|
||||
or, for motivation and design rationale, the __result_of__
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1454.html proposal].
|
||||
|
||||
[#sec:result_of_guidelines]
|
||||
[heading Usage guidelines for __boost_result_of__]
|
||||
|
||||
The following are general suggestions about when and how to use __boost_result_of__.
|
||||
|
||||
# If you are targeting C++11 and are not concerned about portability to
|
||||
non-compliant compilers or previous versions of the standard, then use
|
||||
`__std_result_of__`. If `__std_result_of__` meets your needs, then
|
||||
there's no reason to stop using it.
|
||||
|
||||
# If you are targeting C++11 but may port your code to legacy compilers
|
||||
at some time in the future, then use __boost_result_of__ with __decltype__.
|
||||
When __decltype__ is used __boost_result_of__ and `__std_result_of__` are usually
|
||||
interchangeable. See the documentation on known [link sec:result_of_cxx11_diff differences]
|
||||
between __boost_result_of__ and C++11 __std_result_of__.
|
||||
|
||||
# If compiler portability is required, use __boost_result_of__ with the TR1 protocol
|
||||
|
||||
Regardless of how you configure __boost_result_of__, it is
|
||||
important to bear in mind that the return type of a
|
||||
function may change depending on its arguments, and
|
||||
additionally, the return type of a member function may
|
||||
change depending on the cv-qualification of the
|
||||
object. __boost_result_of__ must be passed
|
||||
the appropriately cv-qualified types in order to
|
||||
deduce the corresponding return type.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
struct functor {
|
||||
int& operator()(int);
|
||||
int const& operator()(int) const;
|
||||
|
||||
float& operator()(float&);
|
||||
float const& operator()(float const&);
|
||||
};
|
||||
|
||||
typedef __boost_result_of__<
|
||||
functor(int)
|
||||
>::type type1; // type1 is int &
|
||||
|
||||
typedef __boost_result_of__<
|
||||
const functor(int)
|
||||
>::type type2; // type2 is int const &
|
||||
|
||||
typedef __boost_result_of__<
|
||||
functor(float&)
|
||||
>::type type3; // type3 is float &
|
||||
|
||||
typedef __boost_result_of__<
|
||||
functor(float const&)
|
||||
>::type type4; // type4 is float const &
|
||||
```
|
||||
|
||||
[#sec:result_of_tr1_protocol_guidelines]
|
||||
[heading Usage guidelines for the TR1 result_of protocol]
|
||||
|
||||
On compliant C++11 compilers, __boost_result_of__ can
|
||||
use __decltype__ to deduce the type of any
|
||||
call expression, including calls to function
|
||||
objects. However, on pre-C++11 compilers or on
|
||||
compilers without adequate decltype support,
|
||||
additional scaffolding is needed from function
|
||||
objects as described above. The following are
|
||||
suggestions about how to use the TR1 protocol.
|
||||
|
||||
* When the return type does not depend on the
|
||||
argument types or the cv-qualification of the
|
||||
function object, simply
|
||||
define `result_type`. There is no need
|
||||
to use the `result` template unless the
|
||||
return type varies.</li>
|
||||
|
||||
* Use the protocol specified type when defining
|
||||
function prototypes. This can help ensure the
|
||||
actual return type does not get out of sync with
|
||||
the protocol specification. For example:
|
||||
|
||||
```
|
||||
struct functor {
|
||||
typedef int result_type;
|
||||
result_type operator()(int);
|
||||
};
|
||||
```
|
||||
|
||||
* Always specify the `result` specialization near the corresponding
|
||||
`operator()` overload. This can make it easier to keep the specializations
|
||||
in sync with the overloads. For example:
|
||||
|
||||
```
|
||||
struct functor {
|
||||
template<class> struct result;
|
||||
|
||||
template<class F>
|
||||
struct result<F(int)> {
|
||||
typedef int& type;
|
||||
};
|
||||
result<functor(int)>::type operator()(int);
|
||||
|
||||
template<class F>
|
||||
struct result<const F(int)> {
|
||||
typedef int const& type;
|
||||
};
|
||||
result<const functor(int)>::type operator()(int) const;
|
||||
};
|
||||
```
|
||||
|
||||
* Use type transformations to simplify
|
||||
the `result` template specialization. For
|
||||
example, the following uses [@../type_traits/doc/html/index.html Boost.TypeTraits]
|
||||
to specialize the `result` template for
|
||||
a single `operator()` that can be called on
|
||||
both a const and non-const function object with
|
||||
either an lvalue or rvalue argument.
|
||||
|
||||
```
|
||||
struct functor {
|
||||
template<class> struct result;
|
||||
|
||||
template<class F, class T>
|
||||
struct result<F(T)>
|
||||
: boost::remove_cv<
|
||||
typename boost::remove_reference<T>::type
|
||||
>
|
||||
{};
|
||||
|
||||
template<class T>
|
||||
T operator()(T const& x) const;
|
||||
};
|
||||
```
|
||||
|
||||
[#sec:result_of_tr1_diff]
|
||||
[heading Known differences between __boost_result_of__ and __boost_tr1_result_of__]
|
||||
|
||||
When using __decltype__, __boost_result_of__ ignores the TR1 protocol and instead deduces the
|
||||
return type of function objects directly via __decltype__. In most situations, users
|
||||
will not notice a difference, so long as they use the protocol correctly. The following are situations in
|
||||
which the type deduced by __boost_result_of__ is known to differ depending on whether
|
||||
__decltype__ or the TR1 protocol is used.
|
||||
|
||||
TR1 protocol misusage: When using the TR1 protocol, __boost_result_of__ cannot
|
||||
detect whether the actual type of a call to a function object is the same as the
|
||||
type specified by the protocol, which allows for the possibility of inadvertent
|
||||
mismatches between the specified type and the actual type. When using __decltype__,
|
||||
these subtle bugs may result in compilation errors. For example:
|
||||
|
||||
```
|
||||
struct functor {
|
||||
typedef short result_type;
|
||||
int operator()(short);
|
||||
};
|
||||
|
||||
#ifdef BOOST_RESULT_OF_USE_DECLTYPE
|
||||
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<__boost_result_of__<functor(short)>::type, int>::value
|
||||
));
|
||||
|
||||
#else
|
||||
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<__boost_result_of__<functor(short)>::type, short>::value
|
||||
));
|
||||
|
||||
#endif
|
||||
```
|
||||
|
||||
Note that the user can force __boost_result_of__ to use the TR1
|
||||
protocol even on platforms that support __decltype__ by
|
||||
defining `BOOST_RESULT_OF_USE_TR1`.
|
||||
|
||||
Nullary function objects: When using the TR1 protocol, __boost_result_of__
|
||||
cannot always deduce the type of calls to nullary function objects, in which case the
|
||||
type defaults to void. When using __decltype__, __boost_result_of__ always gives the
|
||||
actual type of the call expression. For example:
|
||||
|
||||
```
|
||||
struct functor {
|
||||
template<class> struct result {
|
||||
typedef int type;
|
||||
};
|
||||
int operator()();
|
||||
};
|
||||
|
||||
#ifdef BOOST_RESULT_OF_USE_DECLTYPE
|
||||
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<__boost_result_of__<functor()>::type, int>::value
|
||||
));
|
||||
|
||||
#else
|
||||
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<__boost_result_of__<functor()>::type, void>::value
|
||||
));
|
||||
|
||||
#endif
|
||||
```
|
||||
|
||||
Note that there are some workarounds for the nullary function problem.
|
||||
So long as the return type does not vary, `result_type` can always be used to
|
||||
specify the return type regardless of arity. If the return type does vary,
|
||||
then the user can specialize __boost_result_of__ itself for nullary calls.
|
||||
|
||||
Non-class prvalues and cv-qualification: When using the TR1 protocol, __boost_result_of__ will
|
||||
report the cv-qualified type specified by `result_type` or the `result` template regardless of
|
||||
the actual cv-qualification of the call expression. When using __decltype__, __boost_result_of__
|
||||
will report the actual type of the call expression, which is not cv-qualified when the expression
|
||||
is a non-class prvalue. For example:
|
||||
|
||||
```
|
||||
struct functor {
|
||||
template<class> struct result;
|
||||
template<class F, class T> struct result<F(const T)> {
|
||||
typedef const T type;
|
||||
};
|
||||
|
||||
const short operator()(const short);
|
||||
int const & operator()(int const &);
|
||||
};
|
||||
|
||||
// Non-prvalue call expressions work the same with or without decltype.
|
||||
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<
|
||||
__boost_result_of__<functor(int const &)>::type,
|
||||
int const &
|
||||
::value
|
||||
));
|
||||
|
||||
// Non-class prvalue call expressions are not actually cv-qualified,
|
||||
// but only the decltype-based result_of reports this accurately.
|
||||
|
||||
#ifdef BOOST_RESULT_OF_USE_DECLTYPE
|
||||
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<
|
||||
__boost_result_of__<functor(const short)>::type,
|
||||
short
|
||||
::value
|
||||
));
|
||||
|
||||
#else
|
||||
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<
|
||||
__boost_result_of__<functor(const short)>::type,
|
||||
const short
|
||||
::value
|
||||
));
|
||||
|
||||
#endif
|
||||
```
|
||||
|
||||
[#sec:result_of_cxx11_diff]
|
||||
[heading Known differences between __boost_result_of__ and C++11 result_of]
|
||||
|
||||
When using __decltype__, __boost_result_of__ implements most of the C++11 __std_result_of__
|
||||
specification. One known exception is that __boost_result_of__ does not implement the
|
||||
requirements regarding pointers to member data.
|
||||
|
||||
[heading Acknowledgments]
|
||||
|
||||
Created by Doug Gregor. Contributions from Daniel Walker, Eric Niebler, Michel Morin and others.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
[/
|
||||
/ Copyright (c) 2012 Marshall Clow
|
||||
/
|
||||
/ 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)
|
||||
/]
|
||||
|
||||
[article String_Ref
|
||||
[quickbook 1.5]
|
||||
[authors [Clow, Marshall]]
|
||||
[copyright 2012 Marshall Clow]
|
||||
[license
|
||||
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])
|
||||
]
|
||||
]
|
||||
|
||||
[/===============]
|
||||
[section Overview]
|
||||
[/===============]
|
||||
|
||||
Boost.StringRef is an implementation of Jeffrey Yaskin's [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html N3442:
|
||||
string_ref: a non-owning reference to a string].
|
||||
|
||||
When you are parsing/processing strings from some external source, frequently you want to pass a piece of text to a procedure for specialized processing. The canonical way to do this is as a `std::string`, but that has certain drawbacks:
|
||||
|
||||
1) If you are processing a buffer of text (say a HTTP response or the contents of a file), then you have to create the string from the text you want to pass, which involves memory allocation and copying of data.
|
||||
|
||||
2) if a routine receives a constant `std::string` and wants to pass a portion of that string to another routine, then it must create a new string of that substring.
|
||||
|
||||
3) A routine receives a constant `std::string` and wants to return a portion of the string, then it must create a new string to return.
|
||||
|
||||
`string_ref` is designed to solve these efficiency problems. A `string_ref` is a read-only reference to a contiguous sequence of characters, and provides much of the functionality of `std::string`. A `string_ref` is cheap to create, copy and pass by value, because it does not actually own the storage that it points to.
|
||||
|
||||
A `string_ref` is implemented as a small struct that contains a pointer to the start of the character data and a count. A `string_ref` is cheap to create and cheap to copy.
|
||||
|
||||
`string_ref` acts as a container; it includes all the methods that you would expect in a container, including iteration support, `operator []`, `at` and `size`. It can be used with any of the iterator-based algorithms in the STL - as long as you don't need to change the underlying data (`sort` and `remove`, for example, will not work)
|
||||
|
||||
Besides generic container functionality, `string_ref` provides a subset of the interface of `std::string`. This makes it easy to replace parameters of type `const std::string &` with `boost::string_ref`. Like `std::string`, `string_ref` has a static member variable named `npos` to denote the result of failed searches, and to mean "the end".
|
||||
|
||||
Because a `string_ref` does not own the data that it "points to", it introduces lifetime issues into code that uses it. The programmer must ensure that the data that a `string_ref` refers to exists as long as the `string_ref` does.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[/===============]
|
||||
[section Examples]
|
||||
[/===============]
|
||||
|
||||
Integrating `string_ref` into your code is fairly simple. Wherever you pass a `const std::string &` or `std::string` as a parameter, that's a candidate for passing a `boost::string_ref`.
|
||||
|
||||
std::string extract_part ( const std::string &bar ) {
|
||||
return bar.substr ( 2, 3 );
|
||||
}
|
||||
|
||||
if ( extract_part ( "ABCDEFG" ).front() == 'C' ) { /* do something */ }
|
||||
|
||||
Let's figure out what happens in this (contrived) example.
|
||||
|
||||
First, a temporary string is created from the string literal `"ABCDEFG"`, and it is passed (by reference) to the routine `extract_part`. Then a second string is created in the call `std::string::substr` and returned to `extract_part` (this copy may be elided by RVO). Then `extract_part` returns that string back to the caller (again this copy may be elided). The first temporary string is deallocated, and `front` is called on the second string, and then it is deallocated as well.
|
||||
|
||||
Two `std::string`s are created, and two copy operations. That's (potentially) four memory allocations and deallocations, and the associated copying of data.
|
||||
|
||||
Now let's look at the same code with `string_ref`:
|
||||
|
||||
boost::string_ref extract_part ( boost::string_ref bar ) {
|
||||
return bar.substr ( 2, 3 );
|
||||
}
|
||||
|
||||
if ( extract_part ( "ABCDEFG" ).front() == "C" ) { /* do something */ }
|
||||
|
||||
No memory allocations. No copying of character data. No changes to the code other than the types. There are two `string_ref`s created, and two `string_ref`s copied, but those are cheap operations.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[/=================]
|
||||
[section:reference Reference ]
|
||||
[/=================]
|
||||
|
||||
The header file "string_ref.hpp" defines a template `boost::basic_string_ref`, and four specializations - for `char` / `wchar_t` / `char16_t` / `char32_t` .
|
||||
|
||||
`#include <boost/utility/string_ref.hpp>`
|
||||
|
||||
Construction and copying:
|
||||
|
||||
BOOST_CONSTEXPR basic_string_ref (); // Constructs an empty string_ref
|
||||
BOOST_CONSTEXPR basic_string_ref(const charT* str); // Constructs from a NULL-terminated string
|
||||
BOOST_CONSTEXPR basic_string_ref(const charT* str, size_type len); // Constructs from a pointer, length pair
|
||||
template<typename Allocator>
|
||||
basic_string_ref(const std::basic_string<charT, traits, Allocator>& str); // Constructs from a std::string
|
||||
basic_string_ref (const basic_string_ref &rhs);
|
||||
basic_string_ref& operator=(const basic_string_ref &rhs);
|
||||
|
||||
`string_ref` does not define a move constructor nor a move-assignment operator because copying a `string_ref` is just a cheap as moving one.
|
||||
|
||||
Basic container-like functions:
|
||||
|
||||
BOOST_CONSTEXPR size_type size() const ;
|
||||
BOOST_CONSTEXPR size_type length() const ;
|
||||
BOOST_CONSTEXPR size_type max_size() const ;
|
||||
BOOST_CONSTEXPR bool empty() const ;
|
||||
|
||||
// All iterators are const_iterators
|
||||
BOOST_CONSTEXPR const_iterator begin() const ;
|
||||
BOOST_CONSTEXPR const_iterator cbegin() const ;
|
||||
BOOST_CONSTEXPR const_iterator end() const ;
|
||||
BOOST_CONSTEXPR const_iterator cend() const ;
|
||||
const_reverse_iterator rbegin() const ;
|
||||
const_reverse_iterator crbegin() const ;
|
||||
const_reverse_iterator rend() const ;
|
||||
const_reverse_iterator crend() const ;
|
||||
|
||||
Access to the individual elements (all of which are const):
|
||||
|
||||
BOOST_CONSTEXPR const charT& operator[](size_type pos) const ;
|
||||
const charT& at(size_t pos) const ;
|
||||
BOOST_CONSTEXPR const charT& front() const ;
|
||||
BOOST_CONSTEXPR const charT& back() const ;
|
||||
BOOST_CONSTEXPR const charT* data() const ;
|
||||
|
||||
Modifying the `string_ref` (but not the underlying data):
|
||||
|
||||
void clear();
|
||||
void remove_prefix(size_type n);
|
||||
void remove_suffix(size_type n);
|
||||
|
||||
Searching:
|
||||
|
||||
size_type find(basic_string_ref s) const ;
|
||||
size_type find(charT c) const ;
|
||||
size_type rfind(basic_string_ref s) const ;
|
||||
size_type rfind(charT c) const ;
|
||||
size_type find_first_of(charT c) const ;
|
||||
size_type find_last_of (charT c) const ;
|
||||
|
||||
size_type find_first_of(basic_string_ref s) const ;
|
||||
size_type find_last_of(basic_string_ref s) const ;
|
||||
size_type find_first_not_of(basic_string_ref s) const ;
|
||||
size_type find_first_not_of(charT c) const ;
|
||||
size_type find_last_not_of(basic_string_ref s) const ;
|
||||
size_type find_last_not_of(charT c) const ;
|
||||
|
||||
String-like operations:
|
||||
|
||||
BOOST_CONSTEXPR basic_string_ref substr(size_type pos, size_type n=npos) const ; // Creates a new string_ref
|
||||
bool starts_with(charT c) const ;
|
||||
bool starts_with(basic_string_ref x) const ;
|
||||
bool ends_with(charT c) const ;
|
||||
bool ends_with(basic_string_ref x) const ;
|
||||
|
||||
[endsect]
|
||||
|
||||
[/===============]
|
||||
[section History]
|
||||
[/===============]
|
||||
|
||||
[heading boost 1.71]
|
||||
* Glen Fernandes updated the implementation of the stream insertion operator to
|
||||
write directly to the `basic_streambuf` and refactored that functionality into
|
||||
a common utility.
|
||||
|
||||
[heading boost 1.53]
|
||||
* Introduced
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
[/
|
||||
/ Copyright (c) 2012 Marshall Clow
|
||||
/ Copyright (c) 2021, Alan Freitas
|
||||
/
|
||||
/ 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)
|
||||
/]
|
||||
|
||||
[/===============]
|
||||
[section String View]
|
||||
[/===============]
|
||||
|
||||
[heading Introduction]
|
||||
|
||||
The class __boost_string_view__ and other classes derived from __basic_string_view__ represent references to strings or substrings. When you are parsing/processing strings from some external source, frequently you want to pass a piece of text to a procedure for specialized processing. Before __std_string_view__, the canonical way to do this used to be a __std_string__, but that has certain drawbacks:
|
||||
|
||||
1) If you are processing a buffer of text (say a HTTP response or the contents of a file), then you have to create the string from the text you want to pass, which involves memory allocation and copying of data.
|
||||
|
||||
2) If a routine receives a constant __std_string__ and wants to pass a portion of that string to another routine, then it must create a new string of that substring.
|
||||
|
||||
3) If a routine receives a constant __std_string__ and wants to return a portion of the string, then it must create a new string to return.
|
||||
|
||||
__boost_string_view__ is designed to solve these efficiency problems. A __boost_string_view__ is a read-only reference to a contiguous sequence of characters, and provides much of the functionality of __std_string__. A __boost_string_view__ is cheap to create, copy and pass by value, because it does not actually own the storage that it points to.
|
||||
|
||||
A __boost_string_view__ is implemented as a small struct that contains a pointer to the start of the character `data` and a `count`. A __boost_string_view__ is cheap to create and cheap to copy.
|
||||
|
||||
__boost_string_view__ acts as a container; it includes all the methods that you would expect in a container, including iteration support, `operator[]`, `at` and `size`. It can be used with any of the iterator-based algorithms in the STL - as long as you do not need to change the underlying data. For example, __std_sort__ and __std_remove__ will not work.
|
||||
|
||||
Besides generic container functionality, __boost_string_view__ provides a subset of the interface of __std_string__. This makes it easy to replace parameters of type `const __std_string__ &` with __boost_string_view__. Like __std_string__, __boost_string_view__ has a static member variable named `npos` to denote the result of failed searches, and to mean "the end".
|
||||
|
||||
[caution Because a __boost_string_view__ does not own the data that it refers to, it introduces lifetime issues into code that uses it. The programmer must ensure that the data that a __string_view__ refers to exists as long as the __string_view__ does.]
|
||||
|
||||
[note
|
||||
|
||||
Boost.Utility also includes the class __string_ref__:
|
||||
|
||||
- __string_ref__ is the initial implementation of Jeffrey Yaskin's [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html N3442:
|
||||
string_ref: a non-owning reference to a string].
|
||||
|
||||
- __string_view__ is an updated implementation to reflect the Library Fundamentals TS [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4480.html N4480: \[string.view\]]
|
||||
|
||||
Please prefer __string_view__ / __basic_string_view__ over __string_ref__ / __basic_string_ref__:
|
||||
|
||||
- The __basic_string_view__ class better matches __std_basic_string_view__
|
||||
|
||||
- __basic_string_view__ has WAY more constexpr support.
|
||||
|
||||
- Code that uses __basic_string_ref__ should continue to work.
|
||||
|
||||
- No much code depends on __basic_string_ref__ anymore
|
||||
|
||||
|
||||
]
|
||||
|
||||
[/===============]
|
||||
[heading Examples]
|
||||
[/===============]
|
||||
|
||||
Integrating __string_view__ into your code is fairly simple. Wherever you pass a `const __std_string__ &` or __std_string__ as a parameter, that's a candidate for passing a __boost_string_view__.
|
||||
|
||||
```
|
||||
__std_string__ extract_part ( const __std_string__ &bar ) {
|
||||
return bar.substr ( 2, 3 );
|
||||
}
|
||||
|
||||
if ( extract_part ( "ABCDEFG" ).front() == 'C' ) { /* do something */ }
|
||||
```
|
||||
|
||||
Let's figure out what happens in this contrived example.
|
||||
|
||||
* First, a temporary string is created from the string literal `"ABCDEFG"`, and it is passed (by reference) to the routine `extract_part`.
|
||||
* Then a second string is created in the call `__std_string__::substr` and returned to `extract_part` (this copy may be elided by RVO).
|
||||
* Then `extract_part` returns that string back to the caller (again this copy may be elided).
|
||||
* The first temporary string is deallocated, and `front` is called on the second string, and then it is deallocated as well.
|
||||
|
||||
Two __std_string__ s are created, and two copy operations. That is potentially four memory allocations and deallocations, and the associated copying of data.
|
||||
|
||||
Now let's look at the same code with __string_view__:
|
||||
|
||||
```
|
||||
__boost_string_view__ extract_part ( __boost_string_view__ bar ) {
|
||||
return bar.substr ( 2, 3 );
|
||||
}
|
||||
|
||||
if ( extract_part ( "ABCDEFG" ).front() == "C" ) { /* do something */ }
|
||||
```
|
||||
|
||||
No memory allocations. No copying of character data. No changes to the code other than the types. There are two __string_view__ s created, and two __string_view__ s copied, but those are cheap operations.
|
||||
|
||||
[/=================]
|
||||
[heading:reference Synopsis ]
|
||||
[/=================]
|
||||
|
||||
The header file [@../../../include/boost/utility/string_view.hpp `<boost/utility/string_view.hpp>`] defines a template __boost_basic_string_view__, and four specializations __string_view__, __wstring_view__, __u16string_view__, __u32string_view__ - for `char` / `wchar_t` / `char16_t` / `char32_t`.
|
||||
|
||||
`#include <boost/utility/string_view.hpp>`
|
||||
|
||||
Construction and copying:
|
||||
|
||||
```
|
||||
constexpr basic_string_view (); // Constructs an empty string_view
|
||||
constexpr basic_string_view(const charT* str); // Constructs from a NULL-terminated string
|
||||
constexpr basic_string_view(const charT* str, size_type len); // Constructs from a pointer, length pair
|
||||
template<typename Allocator>
|
||||
basic_string_view(const __std_basic_string__<charT, traits, Allocator>& str); // Constructs from a std::string
|
||||
basic_string_view (const basic_string_view &rhs);
|
||||
basic_string_view& operator=(const basic_string_view &rhs);
|
||||
```
|
||||
|
||||
__string_view__ does not define a move constructor nor a move-assignment operator because copying a __string_view__ is just a cheap as moving one.
|
||||
|
||||
Basic container-like functions:
|
||||
|
||||
```
|
||||
constexpr size_type size() const ;
|
||||
constexpr size_type length() const ;
|
||||
constexpr size_type max_size() const ;
|
||||
constexpr bool empty() const ;
|
||||
|
||||
// All iterators are const_iterators
|
||||
constexpr const_iterator begin() const ;
|
||||
constexpr const_iterator cbegin() const ;
|
||||
constexpr const_iterator end() const ;
|
||||
constexpr const_iterator cend() const ;
|
||||
const_reverse_iterator rbegin() const ;
|
||||
const_reverse_iterator crbegin() const ;
|
||||
const_reverse_iterator rend() const ;
|
||||
const_reverse_iterator crend() const ;
|
||||
```
|
||||
|
||||
Access to the individual elements (all of which are const):
|
||||
|
||||
```
|
||||
constexpr const charT& operator[](size_type pos) const ;
|
||||
const charT& at(size_t pos) const ;
|
||||
constexpr const charT& front() const ;
|
||||
constexpr const charT& back() const ;
|
||||
constexpr const charT* data() const ;
|
||||
```
|
||||
|
||||
Modifying the __string_view__ (but not the underlying data):
|
||||
|
||||
```
|
||||
void clear();
|
||||
void remove_prefix(size_type n);
|
||||
void remove_suffix(size_type n);
|
||||
```
|
||||
|
||||
Searching:
|
||||
|
||||
```
|
||||
size_type find(basic_string_view s) const ;
|
||||
size_type find(charT c) const ;
|
||||
size_type rfind(basic_string_view s) const ;
|
||||
size_type rfind(charT c) const ;
|
||||
size_type find_first_of(charT c) const ;
|
||||
size_type find_last_of (charT c) const ;
|
||||
|
||||
size_type find_first_of(basic_string_view s) const ;
|
||||
size_type find_last_of(basic_string_view s) const ;
|
||||
size_type find_first_not_of(basic_string_view s) const ;
|
||||
size_type find_first_not_of(charT c) const ;
|
||||
size_type find_last_not_of(basic_string_view s) const ;
|
||||
size_type find_last_not_of(charT c) const ;
|
||||
```
|
||||
|
||||
String-like operations:
|
||||
|
||||
```
|
||||
constexpr basic_string_view substr(size_type pos, size_type n=npos) const ; // Creates a new string_view
|
||||
bool starts_with(charT c) const ;
|
||||
bool starts_with(basic_string_view x) const ;
|
||||
bool ends_with(charT c) const ;
|
||||
bool ends_with(basic_string_view x) const ;
|
||||
```
|
||||
|
||||
[/===============]
|
||||
[h1 History]
|
||||
[/===============]
|
||||
|
||||
[h5 boost 1.71]
|
||||
* Glen Fernandes updated the implementation of the stream insertion operator to
|
||||
write directly to the `basic_streambuf` and refactored that functionality into
|
||||
a common utility.
|
||||
|
||||
[h5 boost 1.53]
|
||||
* Introduced
|
||||
|
||||
[heading Acknowledgments]
|
||||
|
||||
Author: Clow, Marshall
|
||||
|
||||
Copyright 2012 Marshall Clow
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,564 @@
|
||||
[/
|
||||
/ Copyright (c) 2012 Marshall Clow
|
||||
/ Copyright (c) 2021, Alan Freitas
|
||||
/
|
||||
/ 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)
|
||||
/]
|
||||
|
||||
[/===============]
|
||||
[#sec:value_init]
|
||||
[section Value Init]
|
||||
[/===============]
|
||||
|
||||
[heading Introduction]
|
||||
|
||||
Constructing and initializing objects in a generic way is difficult in
|
||||
C++. The problem is that there are several different rules that apply
|
||||
for initialization. Depending on the type, the value of a newly constructed
|
||||
object can be zero-initialized (logically 0), default-constructed (using
|
||||
the default constructor), or indeterminate. When writing generic code,
|
||||
this problem must be addressed. The template __value_initialized__ provides
|
||||
a solution with consistent syntax for value initialization of scalar,
|
||||
union and class types. Moreover, __value_initialized__ offers a workaround to various
|
||||
compiler issues regarding value-initialization.
|
||||
|
||||
Furthermore, a `const` object __initialized_value__ is provided,
|
||||
to avoid repeating the type name when retrieving the value from a
|
||||
`__value_initialized__<T>` object.
|
||||
|
||||
There are various ways to initialize a variable, in C++. The following
|
||||
declarations all ['may] have a local variable initialized to its default
|
||||
value:
|
||||
|
||||
```
|
||||
T1 var1;
|
||||
T2 var2 = 0;
|
||||
T3 var3 = {};
|
||||
T4 var4 = T4();
|
||||
```
|
||||
|
||||
Unfortunately, whether or not any of those declarations correctly
|
||||
initialize the variable very much depends on its type. The first
|
||||
declaration is valid for any __DefaultConstructible__ type by definition.
|
||||
|
||||
However, it does not always do an initialization. It correctly initializes
|
||||
the variable when it's an instance of a class, and the author of the class
|
||||
has provided a proper default constructor. On the other hand, the value of
|
||||
`var1` is ['indeterminate] when its type is an arithmetic type, like `int`,
|
||||
`float`, or `char`.
|
||||
|
||||
An arithmetic variable is of course initialized properly by the second declaration,
|
||||
`T2 var2 = 0`. But this initialization form will not usually work for a
|
||||
class type, unless the class was especially written to support being
|
||||
initialized that way.
|
||||
|
||||
The third form, `T3 var3 = {}`, initializes an aggregate, typically a "C-style"
|
||||
`struct` or a "C-style" array. However, at the time this library was developed,
|
||||
the syntax did not allow for a class that has an explicitly declared constructor.
|
||||
|
||||
The fourth form is the most generic form of them, as it can be used to initialize
|
||||
arithmetic types, class types, aggregates, pointers, and other types.
|
||||
The declaration, `T4 var4 = T4()`, should be read as follows: First a temporary
|
||||
object is created, by `T4()`. This object is [link sec:valueinit value-initialized].
|
||||
Next the temporary object is copied to the named variable, `var4`. Afterwards,
|
||||
the temporary is destroyed. While the copying and the destruction are likely to
|
||||
be optimized away, C++ still requires the type `T4` to be __CopyConstructible__.
|
||||
So `T4` needs to be ['both] __DefaultConstructible__ ['and] __CopyConstructible__.
|
||||
|
||||
A class may not be CopyConstructible, for example because it may have a
|
||||
private and undefined copy constructor, or because it may be derived from
|
||||
`boost::noncopyable`. Scott Meyers \[[link sec:references 2]\] explains why a
|
||||
class would be defined like that.
|
||||
|
||||
There is another, less obvious disadvantage to the fourth form, `T4 var4 = T4()`:
|
||||
It suffers from various [link sec:compiler_issues compiler issues], causing
|
||||
a variable to be left uninitialized in some compiler specific cases.
|
||||
|
||||
The template __value_initialized__ offers a generic way to initialize
|
||||
an object, like `T4 var4 = T4()`, but without requiring its type
|
||||
to be __CopyConstructible__. And it offers a workaround to those compiler issues
|
||||
regarding value-initialization as well. It allows getting an initialized
|
||||
variable of any type; it ['only] requires the type to be __DefaultConstructible__.
|
||||
A properly ['value-initialized] object of type `T` is constructed by the following
|
||||
declaration:
|
||||
|
||||
```
|
||||
value_initialized<T> var;
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```
|
||||
T var = initialized_value;
|
||||
```
|
||||
|
||||
This form of initialization is semantically equivalent to `T4 var4 = T4()`,
|
||||
but robust against the aforementioned compiler issues.
|
||||
|
||||
[#sec:details]
|
||||
[heading Details]
|
||||
|
||||
The C++ standard \[[link sec:references 3]\] contains the definitions
|
||||
of `zero-initialization` and `default-initialization`. Informally, zero-initialization
|
||||
means that the object is given the initial value `0` converted to the type and
|
||||
default-initialization means that POD \[[link sec:references 4]\] types are zero-initialized,
|
||||
while non-POD class types are initialized with their corresponding default constructors.
|
||||
|
||||
A ['declaration] can contain an ['initializer], which specifies the
|
||||
object's initial value. The initializer can be just '()', which states that
|
||||
the object shall be value-initialized (but see below). However, if a ['declaration]
|
||||
has no ['initializer] and it is of a non-`const`, non-`static` POD type, the
|
||||
initial value is indeterminate: (see §8.5, [dcl.init], for the
|
||||
accurate definitions).
|
||||
|
||||
```
|
||||
int x; // no initializer. x value is indeterminate.
|
||||
__std_string__ s; // no initializer, s is default-constructed.
|
||||
|
||||
int y = int();
|
||||
// y is initialized using copy-initialization
|
||||
// but the temporary uses an empty set of parentheses as the initializer,
|
||||
// so it is default-constructed.
|
||||
// A default constructed POD type is zero-initialized,
|
||||
// therefore, y == 0.
|
||||
|
||||
void foo ( __std_string__ ) ;
|
||||
foo ( __std_string__() ) ;
|
||||
// the temporary string is default constructed
|
||||
// as indicated by the initializer ()
|
||||
```
|
||||
|
||||
[#sec:valueinit]
|
||||
[h5 value-initialization]
|
||||
|
||||
The first [@http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html Technical
|
||||
Corrigendum for the C++ Standard] (TC1), whose draft was released to the public in
|
||||
November 2001, introduced [@http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#178 Core
|
||||
Issue 178], among many other issues.
|
||||
|
||||
That issue introduced the new concept of `value-initialization`, and also fixed the
|
||||
wording for zero-initialization. Informally, value-initialization is similar to
|
||||
default-initialization with the exception that in some cases non-static data members
|
||||
and base class sub-objects are also value-initialized.
|
||||
|
||||
The difference is that an object that is value-initialized will not have, or at least
|
||||
is less likely to have, indeterminate values for data members and base class sub-objects;
|
||||
unlike the case of an object default constructed (see Core Issue 178 for a
|
||||
normative description).
|
||||
|
||||
In order to specify value-initialization of an object we need to use the
|
||||
empty-set initializer: `()`.
|
||||
|
||||
As before, a declaration with no initializer specifies default-initialization,
|
||||
and a declaration with a non-empty initializer specifies copy (`=xxx`) or
|
||||
direct (`xxx`) initialization.
|
||||
|
||||
```
|
||||
template<class T> void eat(T);
|
||||
|
||||
int x ; // indeterminate initial value.
|
||||
|
||||
__std_string__ s; // default-initialized.
|
||||
|
||||
eat ( int() ) ; // value-initialized
|
||||
|
||||
eat ( __std_string__() ) ; // value-initialized
|
||||
```
|
||||
|
||||
[#sec:valueinitsyn]
|
||||
[h5 value-initialization syntax]
|
||||
|
||||
Value initialization is specified using `()`. However, the empty set of
|
||||
parentheses is not permitted by the syntax of initializers because it is
|
||||
parsed as the declaration of a function taking no arguments:
|
||||
|
||||
```
|
||||
int x() ; // declares function int(*)()
|
||||
```
|
||||
|
||||
Thus, the empty `()` must be put in some other initialization context.
|
||||
|
||||
One alternative is to use copy-initialization syntax:
|
||||
|
||||
```
|
||||
int x = int();
|
||||
```
|
||||
|
||||
This works perfectly fine for POD types. But for non-POD class types,
|
||||
copy-initialization searches for a suitable constructor, which could be,
|
||||
for instance, the copy-constructor. It also searches for a suitable conversion
|
||||
sequence but this does not apply in this context.
|
||||
|
||||
For an arbitrary unknown type, using this syntax may not have the
|
||||
value-initialization effect intended because we don't know if a copy
|
||||
from a default constructed object is exactly the same as a default
|
||||
constructed object, and the compiler is allowed, in
|
||||
some cases, but never required to, optimize the copy away.
|
||||
|
||||
One possible generic solution is to use value-initialization of a non static
|
||||
data member:
|
||||
|
||||
```
|
||||
template<class T>
|
||||
struct W
|
||||
{
|
||||
// value-initialization of 'data' here.
|
||||
W() : data() {}
|
||||
|
||||
T data;
|
||||
};
|
||||
|
||||
W<int> w;
|
||||
// w.data is value-initialized for any type.
|
||||
```
|
||||
|
||||
This is the solution as it was supplied by earlier versions of the
|
||||
`__value_initialized__<T>` template class. Unfortunately this approach
|
||||
suffered from various compiler issues.
|
||||
|
||||
[#sec:compiler_issues]
|
||||
[h5 Compiler issues]
|
||||
|
||||
Various compilers have not yet fully implemented value-initialization.
|
||||
So when an object should be ['value-initialized] according to the C++ Standard,
|
||||
it ['may] in practice still be left uninitialized, because of those
|
||||
compiler issues. It is hard to make a general statement on what those issues
|
||||
are like, because they depend on the compiler you are using, its version number,
|
||||
and the type of object you would like to have value-initialized.
|
||||
|
||||
All compilers we have tested so far support value-initialization for arithmetic types properly.
|
||||
However, various compilers may leave some types of ['aggregates] uninitialized, when they
|
||||
should be value-initialized. Value-initialization of objects of a pointer-to-member type may also
|
||||
go wrong on various compilers.
|
||||
|
||||
At the moment of writing, May 2010, the following reported issues regarding
|
||||
value-initialization are still there in current compiler releases:
|
||||
|
||||
|
||||
|
||||
* [@https://connect.microsoft.com/VisualStudio/feedback/details/100744 Microsoft Visual Studio Feedback ID 100744, Value-initialization in new-expression]: Reported by Pavel Kuznetsov (MetaCommunications Engineering), 2005.
|
||||
* [@http://connect.microsoft.com/VisualStudio/feedback/details/484295 Microsoft Visual Studio Feedback ID 484295, VC++ does not value-initialize members of derived classes without user-declared constructor] Reported by Sylvester Hesp, 2009.
|
||||
* [@https://connect.microsoft.com/VisualStudio/feedback/details/499606 Microsoft Visual Studio Feedback ID 499606, Presence of copy constructor breaks member class initialization] Reported by Alex Vakulenko, 2009
|
||||
* [@http://qc.embarcadero.com/wc/qcmain.aspx?d=83751 Embarcadero/C++Builder Report 83751, Value-initialization: arrays should have each element value-initialized] Reported by Niels Dekker (LKEB), 2010.
|
||||
* [@http://qc.embarcadero.com/wc/qcmain.aspx?d=83851 Embarcadero/C++Builder Report 83851, Value-initialized temporary triggers internal backend error C1798] Reported by Niels Dekker, 2010.
|
||||
* [@http://qc.embarcadero.com/wc/qcmain.aspx?d=84279 Embarcadero/C++Builder Report 84279, Internal compiler error (F1004), value-initializing member function pointer by "new T()"] Reported by Niels Dekker, 2010
|
||||
* Sun CR 6947016, Sun 5.10 may fail to value-initialize an object of a non-POD aggregate. Reported to Steve Clamage by Niels Dekker, 2010.
|
||||
* IBM's XL V10.1 and V11.1 may fail to value-initialize a temporary of a non-POD aggregate. Reported to Michael Wong by Niels Dekker, 2010.
|
||||
* Intel support issue 589832, Attempt to value-initialize pointer-to-member triggers internal error on Intel 11.1. Reported by John Maddock, 2010.
|
||||
|
||||
Note that all known GCC issues regarding value-initialization are fixed with GCC version 4.4, including
|
||||
[@http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30111 GCC Bug 30111]. Clang also has completely implemented
|
||||
value-initialization, as far as we know, now that [@http://llvm.org/bugs/show_bug.cgi?id=7139 Clang Bug 7139]
|
||||
is fixed.
|
||||
|
||||
New versions of __value_initialized__ (Boost release version 1.35 or higher) offer a workaround to these
|
||||
issues: __value_initialized__ may now clear its internal data, prior to constructing the object that it
|
||||
contains. It will do so for those compilers that need to have such a workaround, based on the
|
||||
[@boost:/doc/html/config/doc/html/boost_config/boost_macro_reference.html#boost_config.boost_macro_reference.macros_that_describe_defects
|
||||
compiler defect macro] `BOOST_NO_COMPLETE_VALUE_INITIALIZATION`.
|
||||
|
||||
[#sec:types]
|
||||
[heading Types and objects]
|
||||
|
||||
[#sec:val_init]
|
||||
[heading `template class value_initialized<T>`]
|
||||
|
||||
```
|
||||
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__& );
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void swap ( __value_initialized__<T>& lhs, __value_initialized__<T>& rhs )
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
```
|
||||
|
||||
An object of this template class is a `T`-wrapper convertible to `'T&'` whose
|
||||
wrapped object (data member of type `T`) is [link sec:valueinit value-initialized] upon default-initialization
|
||||
of this wrapper class:
|
||||
|
||||
```
|
||||
int zero = 0;
|
||||
__value_initialized__<int> x;
|
||||
assert( x == zero ) ;
|
||||
|
||||
__std_string__ def;
|
||||
__value_initialized__< __std_string__ > y;
|
||||
assert( y == def ) ;
|
||||
```
|
||||
|
||||
The purpose of this wrapper is to provide a consistent syntax for value initialization
|
||||
of scalar, union and class types (POD and non-POD) since the correct syntax for value
|
||||
initialization varies (see [link sec:valueinitsyn value-initialization syntax]).
|
||||
|
||||
The wrapped object can be accessed either through the conversion operator
|
||||
`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
|
||||
```
|
||||
|
||||
Both `const` and non-`const` objects can be wrapped. Mutable objects can be
|
||||
modified directly from within the wrapper but constant objects cannot:
|
||||
|
||||
When `T` is a __Swappable__ type, `__value_initialized__<T>`
|
||||
is swappable as well, by calling its `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
|
||||
```
|
||||
|
||||
[warning
|
||||
|
||||
The __value_initialized__ implementation of Boost version 1.40.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:
|
||||
|
||||
```
|
||||
__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 was that some compilers did not accept the following valid code:
|
||||
|
||||
```
|
||||
struct X
|
||||
{
|
||||
operator int&() ;
|
||||
operator int const&() const ;
|
||||
};
|
||||
X x ;
|
||||
(x == 1) ; // ERROR HERE!
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
]
|
||||
|
||||
[h5 Recommended practice: The non-member get() idiom]
|
||||
|
||||
The obscure behavior of being able to modify a non-`const`
|
||||
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;
|
||||
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
|
||||
```
|
||||
|
||||
[#sec:initialized]
|
||||
[heading `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( __initialized__& );
|
||||
|
||||
private :
|
||||
|
||||
[unspecified] x ;
|
||||
|
||||
};
|
||||
|
||||
template<class T>
|
||||
T const& get ( __initialized__<T> const& x );
|
||||
|
||||
template<class T>
|
||||
T& get ( __initialized__<T>& x );
|
||||
|
||||
template<class T>
|
||||
void swap ( __initialized__<T>& lhs, __initialized__<T>& rhs );
|
||||
|
||||
} // 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.
|
||||
|
||||
[#sec:initialized_value]
|
||||
[heading `initialized_value`]
|
||||
|
||||
```
|
||||
namespace boost {
|
||||
class __initialized_value_t__
|
||||
{
|
||||
public :
|
||||
template <class T> operator T() const ;
|
||||
};
|
||||
|
||||
__initialized_value_t__ const initialized_value = {} ;
|
||||
|
||||
} // namespace boost
|
||||
```
|
||||
|
||||
__initialized_value__ provides a convenient way to get
|
||||
an initialized value: its conversion operator provides an appropriate
|
||||
['value-initialized] object for any __CopyConstructible__ type.
|
||||
|
||||
Suppose you need to have an initialized variable of type `T`.
|
||||
You could do it as follows:
|
||||
|
||||
```
|
||||
T var = T();
|
||||
```
|
||||
|
||||
But as mentioned before, this form suffers from various compiler issues.
|
||||
The template __value_initialized__ offers a workaround:
|
||||
|
||||
```
|
||||
T var = get( __value_initialized__<T>() );
|
||||
```
|
||||
|
||||
Unfortunately both forms repeat the type name, which
|
||||
is rather short now (`T`), but could of course be
|
||||
more like `Namespace::Template<Arg>::Type`.
|
||||
|
||||
Instead, one could use __initialized_value__ as follows:
|
||||
|
||||
```
|
||||
T var = __initialized_value__;
|
||||
```
|
||||
|
||||
[#sec:references]
|
||||
[h5 References]
|
||||
|
||||
# Bjarne Stroustrup, Gabriel Dos Reis, and J. Stephen Adamczyk wrote various papers,
|
||||
proposing to extend the support for brace-enclosed ['initializer lists]
|
||||
in C++. This [@https://en.cppreference.com/w/cpp/language/list_initialization feature] has
|
||||
now been available since C++11. This would allow a variable `var` of any __DefaultConstructible__ type
|
||||
`T` to be ['value-initialized] by doing `T var = {}`. The papers are listed at Bjarne's web page,
|
||||
[@http://www.research.att.com/~bs/WG21.html My C++ Standards committee papers].
|
||||
|
||||
# Scott Meyers, Effective C++, Third Edition, item 6, ['Explicitly disallow the use of
|
||||
compiler-generated functions you do not want], [@http://www.aristeia.com/books.html Scott Meyers: Books and CDs]
|
||||
|
||||
# The C++ Standard, Second edition (2003), ISO/IEC 14882:2003
|
||||
|
||||
# POD stands for "Plain Old Data"
|
||||
|
||||
[#sec:acknowledgements]
|
||||
[h5 Acknowledgements]
|
||||
|
||||
__value_initialized__ was developed by Fernando Cacciola, with help and suggestions
|
||||
from David Abrahams and Darin Adler.
|
||||
|
||||
Special thanks to Bjorn Karlsson who carefully edited and completed this documentation.
|
||||
|
||||
__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 [@mailto:fernando_cacciola@hotmail.com Fernando Cacciola]. The latest version of
|
||||
this file can be found at [@http://www.boost.org www.boost.org].
|
||||
|
||||
[endsect]
|
||||
Reference in new issue
Block a user