1 /*! 2 * \file 3 * \brief outliving_reference_t and related stuff. 4 * 5 * \note 6 * This code is borrowed from cpp_util_3 project 7 * (https://bitbucket.org/sobjectizerteam/cpp_util-3.0) 8 * 9 * \since 10 * v.5.5.19 11 */ 12 13 #pragma once 14 15 #include <so_5/compiler_features.hpp> 16 17 #include <memory> 18 19 namespace so_5 { 20 21 /*! 22 * \brief Helper class for indication of long-lived reference via its type. 23 * 24 * Sometimes it is necessary to store a reference to an object that lives 25 * longer that a reference holder. For example: 26 * \code 27 class config {...}; 28 class config_consumer { 29 config & cfg_; 30 public : 31 config_consumer(config & cfg) : cfg_(cfg) {...} 32 ... 33 }; 34 35 void f() { 36 config cfg = load_config(); // cfg outlives all other objects in f(). 37 config_consumer consumer(cfg); // It is safe to store a reference 38 // for all lifetime of consumer object. 39 ... 40 } 41 * \endcode 42 * 43 * The problem there is: when we see <tt>consumer::consumer(cfg)</tt> we can 44 * say is it safe to pass a reference to short-lived object to it or not. 45 * Helper class outliving_reference_t can be used as indicator that 46 * <tt>consumer::consumer</tt> expects a reference to long-lived object: 47 * \code 48 class config_consumer { 49 so_5::outliving_reference_t<config> cfg_; 50 public : 51 config_consumer(so_5::outliving_reference_t<config> cfg) 52 : cfg_(cfg) 53 {...} 54 ... 55 }; 56 57 void f() { 58 config cfg = load_config(); 59 // An explicit sign that cfg will outlive consumer object. 60 config_consumer consumer(so_5::outliving_mutable(cfg)); 61 ... 62 } 63 * \endcode 64 * 65 * If it is necessary to store a const reference to long-lived object 66 * then outliving_reference_t<const T> and outliving_const() should be used: 67 * \code 68 class data_processor { 69 so_5::outliving_reference_t<const config> cfg_; 70 public : 71 data_processor(so_5::outliving_reference_t<const config> cfg) 72 : cfg_(cfg) 73 {...} 74 ... 75 }; 76 77 void f() { 78 config cfg = load_config(); 79 config_consumer consumer(so_5::outliving_mutable(cfg)); 80 data_processor processor(so_5::outliving_const(cfg)); 81 ... 82 } 83 * \endcode 84 * 85 * \attention 86 * outliving_reference_t has no copy operator! It is CopyConstructible, 87 * but not CopyAssingable class. 88 * 89 * \tparam T type for reference. 90 * 91 * \since 92 * v.5.5.19 93 */ 94 template< typename T > 95 class outliving_reference_t 96 { 97 T * m_ptr; 98 99 public : 100 using type = T; 101 outliving_reference_t(T & r)102 explicit outliving_reference_t(T & r) noexcept : m_ptr(std::addressof(r)) {} 103 104 outliving_reference_t(T &&) = delete; outliving_reference_t(outliving_reference_t const & o)105 outliving_reference_t(outliving_reference_t const & o) noexcept 106 : m_ptr(std::addressof(o.get())) 107 {} 108 109 template<typename U> outliving_reference_t(outliving_reference_t<U> const & o)110 outliving_reference_t(outliving_reference_t<U> const & o) noexcept 111 : m_ptr(std::addressof(o.get())) 112 {} 113 114 outliving_reference_t & operator=(outliving_reference_t const &o) = delete; 115 operator T&() const116 operator T&() const noexcept { return this->get(); } 117 get() const118 T & get() const noexcept { return *m_ptr; } 119 }; 120 121 /*! 122 * \brief Make outliving_reference wrapper for mutable reference. 123 * 124 * \sa outliving_reference_t 125 * 126 * \since 127 * v.5.5.19 128 */ 129 template< typename T > 130 outliving_reference_t< T > outliving_mutable(T & r)131outliving_mutable( T & r ) { return outliving_reference_t<T>(r); } 132 133 /*! 134 * \brief Make outliving_reference wrapper for const reference. 135 * 136 * \sa outliving_reference_t 137 * 138 * \since 139 * v.5.5.19 140 */ 141 template< typename T > 142 outliving_reference_t< const T > outliving_const(T const & r)143outliving_const( T const & r ) { return outliving_reference_t<const T>(r); } 144 145 /*! 146 * \brief Make outliving_reference wrapper for const reference. 147 * 148 * \sa outliving_reference_t 149 * 150 * \since 151 * v.5.5.22 152 */ 153 template< typename T > 154 outliving_reference_t< const T > outliving_const(outliving_reference_t<T> r)155outliving_const( outliving_reference_t<T> r ) { return outliving_reference_t<const T>(r.get()); } 156 157 } /* namespace so_5 */ 158 159