I created a simple custom refernce_wrapper
class template, which, in contrast to std::reference_wrapper
, has some additional functionality:
- It recognizes an empty state (which allows deferring binding).
It provides a rebinding option.(As noted in comments, this is actually possible with the copy assignment operator ofstd::reference_wrapper
.)- It defines
operator->()
for direct access to members of the referenced object.
Here is a simple code that illustrates this functionality:
Derived d;
reference_wrapper<Base> rw; // impossible with std::reference_wrapper
rw = d; // deferred binding
rw->memfn(); // 'rw.get().memfn()' with std::reference_wrapper
My implementation is as follows:
template <typename T>
class reference_wrapper
{
T* ptr_;
public:
reference_wrapper() : ptr_(nullptr) { }
reference_wrapper(const reference_wrapper&) = default;
template <typename U>
reference_wrapper(U& obj) : ptr_(&obj) { }
reference_wrapper& operator=(const reference_wrapper&) = default;
template <typename U>
reference_wrapper& operator=(U& obj)
{
ptr_ = &obj;
return *this;
}
bool empty() const { return ptr_ == nullptr; }
T& get() const
{
assert(!empty());
return *ptr_;
}
operator T&() const { return get(); }
T* operator->() const
{
assert(!empty());
return ptr_;
}
void clear() { ptr_ = nullptr; }
};
template <typename T>
inline auto ref(T& r)
{
return reference_wrapper<T>(r);
}
template <typename T>
inline auto cref(const T& r)
{
return reference_wrapper<const T>(r);
}
Complete live demo link: https://godbolt.org/z/MGYnWKo7o
Notes:
- I don't care about binding rvalues.
- For performance reasons, I want to avoid unnecessary branching in production builds. This is why the access to the referenced value is protected with assertions.
Rationale:
Why am I not using a pointer instead?
- I don't like raw pointers to be used in high-level application code.
- I want the access to the referenced object to be protected with assertions.
I will appreciate any comments/suggestions for improvement if anyone finds anything wrong with this code.
std::reference_wrapper
. \$\endgroup\$std::optional<std::reference_wrapper<T>>
, I don't like this option at all. First, it is memory-inefficient (the internal pointer can recognize the empty state by itself, whileoptional
needs an additional flag). Second, the access to the members of the referenced object requiresrw->get().f()
instead of simplerw->f()
. \$\endgroup\$