technicalities.rst 2.6 KB

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