A maybe type for C++ A maybe type for C++
Blog
Codex
A maybe type for C++
Posted June 18, 2026 3 min read Here’s an idea I had for a useful C++ class that adds a little syntactic sugar to null pointer checking.<br>I’ve come up with an interesting little utility class that I use to make null pointer checking a little nicer to write.I’ve called it maybe_ptr. It’s a template class that holds a null-able pointer value. The trick it performs is to provide null-safe access to the referenced value through the range-based for syntax. Here’s what that looks like in practice. getCounter(bool can_count)<br>if (can_count)<br>return { &g_counter };<br>return { };
int main()<br>for (auto&& counter : getCounter(true))<br>counter++; // this statement gets executed
for (auto&& counter: getCounter(false))<br>counter++; // this statement does not
cout 1static int g_counter=0;<br>3maybe_ptrint> getCounter(bool can_count)<br>4{<br>5 if (can_count)<br>6 return { &g_counter };<br>7 return { };<br>8}<br>10int main()<br>11{<br>12 for (auto&& counter : getCounter(true))<br>13 counter++; // this statement gets executed<br>14<br>15 for (auto&& counter: getCounter(false))<br>16 counter++; // this statement does not<br>17<br>18 cout g_counter endl; // prints 1<br>19 return 0;<br>20}<br>This is certainly a little strange, and definitely a hack on the syntax of the for loop. But I think it does a good job expressing the intent in a really concise and readable way.In this example I want to increment the global counter, but it isn’t always possible to do so because of the can_count parameter. My use of the maybe_ptr ensures that the loop only emits counter once, and only if the underlying pointer isn’t null.Here’s an implementation of the class. class maybe_iterator<br>T* ptr=nullptr;
public:<br>using iterator_category = std::random_access_iterator_tag;<br>using value_type = T;<br>using difference_type = std::ptrdiff_t;<br>using pointer = T*;<br>using reference = T&;
constexpr maybe_iterator(T* p = nullptr) : ptr(p) {}
constexpr reference operator*() const { return *ptr; }<br>constexpr pointer operator->() const { return ptr; }
constexpr maybe_iterator& operator++() { ptr = nullptr; return *this; }<br>constexpr maybe_iterator operator++(int) { auto tmp = *this; ++(*this); return tmp; }
constexpr bool operator==(maybe_iterator const& other) const { return ptr == other.ptr; }<br>constexpr bool operator!=(maybe_iterator const& other) const { return ptr != other.ptr; }<br>};
template struct maybe_ptr<br>T* ptr=nullptr;
auto begin() { return maybe_iterator(ptr); }<br>auto end() { return maybe_iterator(nullptr); }<br>};" data-code-lang=cpp> 1templatetypename T> class maybe_iterator<br>2{<br>3 T* ptr=nullptr;<br>5public:<br>6 using iterator_category = std::random_access_iterator_tag;<br>7 using value_type = T;<br>8 using difference_type = std::ptrdiff_t;<br>9 using pointer = T*;<br>10 using reference = T&;<br>11<br>12 constexpr maybe_iterator(T* p = nullptr) : ptr(p) {}<br>13<br>14 constexpr reference operator*() const { return *ptr; }<br>15 constexpr pointer operator->() const { return ptr; }<br>16<br>17 constexpr maybe_iterator& operator++() { ptr = nullptr; return *this; }<br>18 constexpr maybe_iterator operator++(int) { auto tmp = *this; ++(*this); return tmp; }<br>19<br>20 constexpr bool operator==(maybe_iterator const& other) const { return ptr == other.ptr; }<br>21 constexpr bool operator!=(maybe_iterator const& other) const { return ptr != other.ptr; }<br>22};<br>23<br>24template typename T> struct maybe_ptr<br>25{<br>26 T* ptr=nullptr;<br>27<br>28 auto begin() { return maybe_iteratorT>(ptr); }<br>29 auto end() { return maybe_iteratorT>(nullptr); }<br>30};<br>The class has the requisite begin() end() methods which allow it to interact with the range-based for loop. The additional iterator class does the null check. It says “if the pointer is not null, dereference and emit. If it is null, iteration has ended” Another perspective is that this is an iterable object that has precisely zero or one element, dependent on the null-ness of the underlying pointer.This isn’t my original idea, not entirely. It’s a riff on the new proposal for std::optional in C++26, which has a very similar design and rationale. My class is specifically adapted for handling null-able pointers in the same elegant way.Did you find this useful? Do you have any interesting C++ tricks of your own? If so, let me know!<br>Send a message to mail@lzon.ca, or DM me on one of my social accounts on the homepage.
Settings<br>Theme
Primary<br>Secondary<br>Tertiary
Secrets