Technicalities - Boost.GIL documentation

###  | #  |

# Technicalities

## Creating a reference proxy

Sometimes it is necessary to create a proxy class that represents a reference to a given object. Examples of these are GIL’s reference to a planar pixel (`planar_pixel_reference`) and GIL’s sub-byte channel references. Writing a reference proxy class can be tricky. One problem is that the proxy reference is constructed as a temporary object and returned by value upon dereferencing the iterator:

    struct rgb_planar_pixel_iterator
    {
     typedef my_reference_proxy<T> reference;
     reference operator*() const { return reference(red,green,blue); }
    };

The problem arises when an iterator is dereferenced directly into a function that takes a mutable pixel:

    template <typename Pixel>    // Models MutablePixelConcept
    void invert_pixel(Pixel& p);

    rgb_planar_pixel_iterator myIt;
    invert_pixel(*myIt);        // compile error!

C++ does not allow for matching a temporary object against a non-constant reference. The solution is to:

- Use const qualifier on all members of the reference proxy object:

    template <typename T>
    struct my_reference_proxy
    {
      const my_reference_proxy& operator=(const my_reference_proxy& p) const;
      const my_reference_proxy* operator->() const { return this; }
      ...
    };

- Use different classes to denote mutable and constant reference (maybe based on the constness of the template parameter)

- Define the reference type of your iterator with const qualifier:

    struct iterator_traits<rgb_planar_pixel_iterator>
    {
      typedef const my_reference_proxy<T> reference;
    };

A second important issue is providing an overload for `swap` for your reference class. The default `std::swap` will not work correctly. You must use a real value type as the temporary. A further complication is that in some implementations of the STL the `swap` function is incorrectly called qualified, as `std::swap`. The only way for these STL algorithms to use your overload is if you define it in the `std` namespace:

    namespace std
    {
     template <typename T>
     void swap(my_reference_proxy<T>& x, my_reference_proxy<T>& y)
     {
        my_value<T> tmp=x;
        x=y;
        y=tmp;
     }
    }

Lastly, remember that constructors and copy-constructors of proxy references are always shallow and assignment operators are deep.

We are grateful to Dave Abrahams, Sean Parent and Alex Stepanov for suggesting the above solution.