Skip to content

Instantly share code, notes, and snippets.

@ShirenY
Last active January 12, 2026 03:54
Show Gist options
  • Select an option

  • Save ShirenY/4ce18484b45e2554e2a57470fff121bf to your computer and use it in GitHub Desktop.

Select an option

Save ShirenY/4ce18484b45e2554e2a57470fff121bf to your computer and use it in GitHub Desktop.
Ref<T> A zero-overhead, nullable, rebindable smart reference
#ifndef MODERN_REF_HPP
#define MODERN_REF_HPP
#include <type_traits>
#include <functional>
#include <optional>
#include <cassert>
/**
* @brief Ref<T> - A zero-overhead, nullable, rebindable smart reference.
* * This class mimics a raw pointer but forbids pointer arithmetic and
* provides a cleaner interface. It is exactly the size of a raw pointer.
*/
template <typename T>
class Ref {
private:
T* _ptr;
template <typename U> friend class Ref;
public:
// --- Lifecycle ---
Ref() noexcept : _ptr(nullptr) {}
Ref(std::nullopt_t) noexcept : _ptr(nullptr) {}
Ref(std::nullptr_t) noexcept : _ptr(nullptr) {}
// Bind to an lvalue; rvalue binding is strictly deleted
Ref(T& obj) noexcept : _ptr(&obj) {}
Ref(T&&) = delete;
// Covariant conversion: Ref<T> -> Ref<const T>
template <typename U, typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
Ref(const Ref<U>& other) noexcept : _ptr(other._ptr) {}
Ref& operator=(std::nullopt_t) noexcept { _ptr = nullptr; return *this; }
Ref& operator=(T& obj) noexcept { _ptr = &obj; return *this; }
Ref& operator=(T&&) = delete;
// --- Access ---
T* operator->() const {
assert(_ptr != nullptr && "Ref access error: Ref is empty");
return _ptr;
}
T& operator*() const {
assert(_ptr != nullptr && "Ref dereference error: Ref is empty");
return *_ptr;
}
T& get() const {
assert(_ptr != nullptr && "Ref get error: Ref is empty");
return *_ptr;
}
// --- Status & Comparison ---
explicit operator bool() const noexcept { return _ptr != nullptr; }
bool has_value() const noexcept { return _ptr != nullptr; }
bool operator==(const Ref& other) const noexcept {
if (_ptr == other._ptr)
return true;
if (!_ptr || !other._ptr)
return false;
return *_ptr == *other._ptr;
}
bool operator!=(const Ref& other) const noexcept { return !(this->operator == (other)); }
bool operator==(std::nullptr_t) const noexcept { return _ptr == nullptr; }
bool operator!=(std::nullptr_t) const noexcept {return _ptr != nullptr;}
};
// --- Standard Library Specialization ---
namespace std {
template <typename T>
struct hash<Ref<T>> {
size_t operator()(const Ref<T>& ref) const noexcept {
// We hash the address, consistent with pointer-like semantics
return ref.has_value() ? std::hash<T*>{}(&ref.get()) : 0;
}
};
}
/*
// --- Usage Example ---
#include <iostream>
#include <unordered_set>
int main() {
int x = 10, y = 20;
Ref<int> rx = x;
Ref<int> ry = y;
std::unordered_set<Ref<int>> set;
set.insert(rx);
set.insert(ry);
std::cout << "Set size: " << set.size() << std::endl; // Should be 2
if (set.count(rx)) {
std::cout << "Found x by its reference!" << std::endl;
}
return 0;
}
*/
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment