Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / gil / doc / design / technicalities.rst
1 Technicalities
2 ==============
3
4 .. contents::
5    :local:
6    :depth: 2
7
8 Creating a reference proxy
9 --------------------------
10
11 Sometimes it is necessary to create a proxy class that represents a
12 reference to a given object. Examples of these are GIL's reference to
13 a planar pixel (``planar_pixel_reference``) and GIL's sub-byte channel
14 references. Writing a reference proxy class can be tricky. One problem
15 is that the proxy reference is constructed as a temporary object and
16 returned by value upon dereferencing the iterator:
17
18 .. code-block:: cpp
19
20   struct rgb_planar_pixel_iterator
21   {
22    typedef my_reference_proxy<T> reference;
23    reference operator*() const { return reference(red,green,blue); }
24   };
25
26 The problem arises when an iterator is dereferenced directly into a
27 function that takes a mutable pixel:
28
29 .. code-block:: cpp
30
31   template <typename Pixel>    // Models MutablePixelConcept
32   void invert_pixel(Pixel& p);
33
34   rgb_planar_pixel_iterator myIt;
35   invert_pixel(*myIt);        // compile error!
36
37 C++ does not allow for matching a temporary object against a non-constant
38 reference. The solution is to:
39
40 * Use const qualifier on all members of the reference proxy object:
41
42 .. code-block:: cpp
43
44     template <typename T>
45     struct my_reference_proxy
46     {
47       const my_reference_proxy& operator=(const my_reference_proxy& p) const;
48       const my_reference_proxy* operator->() const { return this; }
49       ...
50     };
51
52 * Use different classes to denote mutable and constant reference
53   (maybe based on the constness of the template parameter)
54
55 * Define the reference type of your iterator with const qualifier:
56
57 .. code-block:: cpp
58
59     struct iterator_traits<rgb_planar_pixel_iterator>
60     {
61       typedef const my_reference_proxy<T> reference;
62     };
63
64 A second important issue is providing an overload for ``swap`` for
65 your reference class. The default ``std::swap`` will not work
66 correctly. You must use a real value type as the temporary. A further
67 complication is that in some implementations of the STL the ``swap``
68 function is incorrectly called qualified, as ``std::swap``. The only
69 way for these STL algorithms to use your overload is if you define it
70 in the ``std`` namespace:
71
72 .. code-block:: cpp
73
74   namespace std
75   {
76    template <typename T>
77    void swap(my_reference_proxy<T>& x, my_reference_proxy<T>& y)
78    {
79       my_value<T> tmp=x;
80       x=y;
81       y=tmp;
82    }
83   }
84
85 Lastly, remember that constructors and copy-constructors of proxy
86 references are always shallow and assignment operators are deep.
87
88 We are grateful to Dave Abrahams, Sean Parent and Alex Stepanov for
89 suggesting the above solution.