File indexing completed on 2024-05-12 04:44:32
0001 // SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com> 0002 // SPDX-License-Identifier: BSD-2-Clause OR MIT 0003 0004 #ifndef CONSTPROPAGATINGRAWPOINTER_H 0005 #define CONSTPROPAGATINGRAWPOINTER_H 0006 0007 namespace PerceptualColor 0008 { 0009 /** @internal 0010 * 0011 * @brief A <tt>const</tt> propagating raw pointer 0012 * 0013 * With normal raw C++ pointers (and also with <tt>std::unique_ptr</tt> 0014 * pointers), within <tt>const</tt> functions you can do non-const 0015 * operations <em>on objects that a pointer points to</em>. 0016 * 0017 * <em>This</em> pointer type is different: It propagates the const-ness of 0018 * the object members and propagates them to the call through the pointer; 0019 * it will trigger a compiler error if non-cost access to object members 0020 * or methods is done from within const functions. Apart from that, it 0021 * behaves similar to raw pointers. For compatibility with raw pointers, 0022 * it also casts implicitly to the corresponding raw pointer (but only 0023 * within non-<tt>const</tt> contexts). 0024 * 0025 * Think of this template as a simple alternative to 0026 * <tt>std::experimental::propagate_const< T* ></tt> 0027 * 0028 * Example code: 0029 * @snippet testconstpropagatingrawpointer.cpp example 0030 * 0031 * @note Currently, this class does not implement assignment operators 0032 * or assignment constructors. Once constructed, an instance of 0033 * this class cannot be changed anymore. 0034 * 0035 * @note A @ref ConstPropagatingRawPointer pointer variable itself 0036 * may not be const! (Otherwise, this would make <tt>const</tt> 0037 * <em>all</em> access even to non-const functions of the pointed 0038 * object.) 0039 * 0040 * @sa @ref ConstPropagatingUniquePointer 0041 * 0042 * @note There exist very sophisticated implementations like 0043 * https://github.com/jbcoe/propagate_const but we use nevertheless 0044 * our own light-wise implementation because this seems to be enough 0045 * for our limited use case. 0046 * 0047 * @note This class could be replaced in the future by <tt> 0048 * <a href="https://en.cppreference.com/w/cpp/experimental/propagate_const"> 0049 * std::experimental::propagate_const</a></tt> if this one ever becomes 0050 * part of the C++ standard. (Experimental features however are optional 0051 * for compilers, so not all of them implement them. Furthermore, they 0052 * can still change. Therefore, we cannot use experimental features here.) */ 0053 template<typename T> 0054 class ConstPropagatingRawPointer final 0055 { 0056 public: 0057 /** @brief Default constructor 0058 * 0059 * Creates a pointer that points to <tt>nullptr</tt>. */ 0060 explicit ConstPropagatingRawPointer() 0061 : m_pointer(nullptr) 0062 { 0063 } 0064 0065 /** @brief Constructor 0066 * 0067 * @param pointer Object to which to point */ 0068 explicit ConstPropagatingRawPointer(T *pointer) 0069 : m_pointer(pointer) 0070 { 0071 } 0072 0073 /** @brief Default destructor */ 0074 ~ConstPropagatingRawPointer() noexcept = default; 0075 0076 /** @brief Non-const pointer operator 0077 * 0078 * @returns Non-const pointer operator */ 0079 [[nodiscard]] T *operator->() 0080 { 0081 return m_pointer; 0082 } 0083 0084 /** @brief Const pointer operator 0085 * 0086 * @returns Const pointer */ 0087 [[nodiscard]] const T *operator->() const 0088 { 0089 return m_pointer; 0090 } 0091 0092 /** @brief Non-const dereference operator 0093 * 0094 * @returns Non-const dereference operator */ 0095 [[nodiscard]] T &operator*() 0096 { 0097 return *m_pointer; 0098 } 0099 0100 /** @brief Const dereference operator 0101 * 0102 * @returns Const dereference operator */ 0103 [[nodiscard]] const T &operator*() const 0104 { 0105 return *m_pointer; 0106 } 0107 0108 /** @brief Cast to a normal raw pointer. 0109 * 0110 * @sa @ref toPointerToConstObject() */ 0111 [[nodiscard]] operator T *() 0112 { 0113 return m_pointer; 0114 } 0115 0116 /** @brief Cast to a normal raw pointer that points to a const object. 0117 * 0118 * @returns Cast to a normal raw pointer that points to a const object. 0119 * 0120 * @sa @ref operator T *() */ 0121 // We could provide a const overload to operator T*() instead of 0122 // providing this function with a strange name. But overloading 0123 // operator T* leads to compile errors because of ambiguity 0124 // on GCC and Clang when using this pointer within a “delete” statement. 0125 // That’s confusing, therefore we should avoid it. So given this 0126 // function this different name prevents automatic casts in non-cost 0127 // objects, which also forbids deleting directly pointers of this 0128 // type in non-const contexts, which is nice. 0129 [[nodiscard]] const T *toPointerToConstObject() const 0130 { 0131 return m_pointer; 0132 } 0133 0134 private: 0135 /** @brief Internal storage for the pointer */ 0136 T *m_pointer; 0137 }; 0138 0139 } // namespace PerceptualColor 0140 0141 #endif // CONSTPROPAGATINGUNIQUEPOINTER_H