• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1Technicalities
2==============
3
4.. contents::
5   :local:
6   :depth: 2
7
8Creating a reference proxy
9--------------------------
10
11Sometimes it is necessary to create a proxy class that represents a
12reference to a given object. Examples of these are GIL's reference to
13a planar pixel (``planar_pixel_reference``) and GIL's sub-byte channel
14references. Writing a reference proxy class can be tricky. One problem
15is that the proxy reference is constructed as a temporary object and
16returned 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
26The problem arises when an iterator is dereferenced directly into a
27function 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
37C++ does not allow for matching a temporary object against a non-constant
38reference. 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
64A second important issue is providing an overload for ``swap`` for
65your reference class. The default ``std::swap`` will not work
66correctly. You must use a real value type as the temporary. A further
67complication is that in some implementations of the STL the ``swap``
68function is incorrectly called qualified, as ``std::swap``. The only
69way for these STL algorithms to use your overload is if you define it
70in 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
85Lastly, remember that constructors and copy-constructors of proxy
86references are always shallow and assignment operators are deep.
87
88We are grateful to Dave Abrahams, Sean Parent and Alex Stepanov for
89suggesting the above solution.
90