The idea being you can have a simple type called maybe
that wraps another type, which provides the ability to possibly not return a value from a function. I'm sure it's not perfect yet, but it's got the broad strokes I'm looking for. I'm mostly looking for corner cases I've missed and anything else I've overlooked.
#ifndef MAYBE_H_
#define MAYBE_H_
#include <exception>
namespace {
// implementation enabled for non-reference types
template <class T>
struct maybe {
maybe() : valid(false) {} // default constructor
maybe(const T& val) : valid(true) { // contructor from wrapped value
new ((void*)storage) T(val);
}
maybe(const maybe &other) { // copy constructor
valid = other.valid;
if (valid) {
new ((void*)storage) T(other.get_ref());
}
}
maybe(maybe &&other) : maybe() { // move constructor
std::swap(valid, other.valid);
std::swap(storage, other.storage);
}
~maybe() { // destructor
if (valid) {
get_ref().~T();
}
}
// assignment operator, uses copy-and-swap trick
maybe& operator =(maybe other) {
swap(*this, other);
return *this;
}
// type-coercion operator to get back to wrapped value
// calling without checking validity causes bad_exception
operator T&() {
if (!valid) {
throw std::bad_exception();
}
return get_ref();
}
// for checking validity of container
explicit operator bool() { return valid; }
private:
bool valid;
alignas(T) char storage[sizeof(T)];
T& get_ref() const { return *static_cast<T*>((void*)storage); }
};
// implementation enabled for reference types
template <class T>
struct maybe<T&> {
maybe() : valid(false) value(nullptr) {}
maybe(T& val) : valid(true), value(&val) {}
maybe(const maybe &other) : valid(other.valid), value(other.value) {}
operator T&() {
if (!valid) {
throw std::bad_exception();
}
return *value;
}
explicit operator bool() { return valid; }
private:
bool valid;
T* value;
};
} // namespace {
#endif//MAYBE_H_