summaryrefslogtreecommitdiff
path: root/libs/optional/doc/15_in_place_factories.qbk
blob: d9df24d06457e62acb0daac8d7c92a34eab5516d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139

[section In-Place Factories]

One of the typical problems with wrappers and containers is that their
interfaces usually provide an operation to initialize or assign the
contained object as a copy of some other object. This not only requires the
underlying type to be __COPY_CONSTRUCTIBLE__, but also requires the existence of
a fully constructed object, often temporary, just to follow the copy from:

    struct X
    {
        X ( int, std::string ) ;
    } ;

    class W
    {
        X wrapped_ ;

        public:

        W ( X const& x ) : wrapped_(x) {}
    } ;

    void foo()
    {
        // Temporary object created.
        W ( 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 only needs to supply the arguments to the
constructor to use in the wrapped object construction.

    class W
    {
        X wrapped_ ;

        public:

        W ( X const& x ) : wrapped_(x) {}
        W ( int a0, std::string a1) : wrapped_(a0,a1) {}
    } ;

    void foo()
    {
        // Wrapped object constructed in-place
        // No temporary created.
        W (123,"hello") ;
    }

A limitation of this method is that it doesn't scale well to wrapped
objects with multiple constructors nor to generic code were the constructor
overloads are unknown.

The solution presented in this library is the family of [*InPlaceFactories]
and [*TypedInPlaceFactories].
These factories are a family of classes which encapsulate an increasing
number of arbitrary constructor parameters and supply a method to construct
an object of a given type using those parameters at an address specified by
the user via placement new.

For example, one member of this family looks like:

    template<class T,class A0, class A1>
    class TypedInPlaceFactory2
    {
        A0 m_a0 ; A1 m_a1 ;

        public:

        TypedInPlaceFactory2( A0 const& a0, A1 const& a1 ) : m_a0(a0), m_a1(a1) {}

        void construct ( void* p ) { new (p) T(m_a0,m_a1) ; }
     } ;

A wrapper class aware of this can use it as:

    class W
    {
        X wrapped_ ;

        public:

        W ( X const& x ) : wrapped_(x) {}
        W ( TypedInPlaceFactory2 const& fac ) { fac.construct(&wrapped_) ; }
    } ;

    void foo()
    {
        // Wrapped object constructed in-place via a TypedInPlaceFactory.
        // No temporary created.
        W ( TypedInPlaceFactory2<X,int,std::string>(123,"hello")) ;
    }

The factories are divided in two groups:

* [_TypedInPlaceFactories]: those which take the target type as a primary
template parameter.
* [_InPlaceFactories]: those with a template `construct(void*)` member
function taking the target type.

Within each group, all the family members differ only in the number of
parameters allowed.

This library provides an overloaded set of helper template functions to
construct these factories without requiring unnecessary template parameters:

    template<class A0,...,class AN>
    InPlaceFactoryN <A0,...,AN> in_place ( A0 const& a0, ..., AN const& aN) ;

    template<class T,class A0,...,class AN>
    TypedInPlaceFactoryN <T,A0,...,AN> in_place ( T const& a0, A0 const& a0, ..., AN const& aN) ;

In-place factories can be used generically by the wrapper and user as follows:

    class W
    {
        X wrapped_ ;

        public:

        W ( X const& x ) : wrapped_(x) {}

        template< class InPlaceFactory >
        W ( InPlaceFactory const& fac ) { fac.template <X>construct(&wrapped_) ; }

    } ;

    void foo()
    {
        // Wrapped object constructed in-place via a InPlaceFactory.
        // No temporary created.
        W ( in_place(123,"hello") ) ;
    }

The factories are implemented in the headers: __IN_PLACE_FACTORY_HPP__ and __TYPED_IN_PLACE_FACTORY_HPP__

[endsect]