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