Awesome
Option/Sum Types for Qt Projects
A set of simple(ish) C++ templates which implement sum and option
types. They serve a similar purpose to boost::variant
and boost::optional
but are implemented on top of Qt's QVariant container.
Update (2017-09-23): A variant
class has been added to the C++ standard library for C++17 (std::variant) and you can find polyfills for compilers that don't ship with it yet. Consider using that instead of this code in your project.
Templates
Either
Either<T1,T2>
represents either a value of type T1
or
a value of type T2
. You can think of it as a QVariant which is restricted
to being either a T1
or T2
rather than any type which QVariant supports.
Either<T1,T2>
instances can be constructed directly from an instance
of T1
or T2
or by using the some(T)
function which returns a type that
can be implicitly cast to any Either
type that has T
as one of its
types.
Simple example:
// parse a value which might either be a
// string or an integer
Either<QString,int> value = parseValue(data);
if (value.is1st()) {
qDebug() << "Read string " << value.as1st();
} else {
qDebug() << "Read integer " << value.as2nd();
}
Maybe
Maybe<T>
represents either a value of type T or no value. You can think of it
as a QVariant which is restricted to either being a T or a null type.
Maybe<T>
instances are constructed using the just(T)
or nothing()
functions.
just(T)
handles pointers specially. If passed a null pointer it returns
a Maybe
representing no value. This is useful when working with existing code
which uses a null pointer to represent no value.
Simple example:
// try to read the size of a file, which may fail if
// the file is not readable
Maybe<int> size = fileSize(path);
if (size) {
std::cout << "file size is " << size.value() << " bytes" << std::endl;
} else {
std::cout << "could not read file size" << std::endl;
}
Examples
See TestMaybe.cpp
for unit tests which show example usage of the Maybe
and
Either
templates.
Performance
The templates use QVariant
as the underlying storage and the same performance considerations apply. A QVariant in Qt 4 is 12 bytes in size on most platforms - 8 bytes for the data itself or a pointer to the data, plus 4 bytes for the type tag and flags. Pointers and primitive types of 8 bytes in size or less are stored within the QVariant. Larger types are stored in heap-allocated storage.
Exceptions
Unlike boost::variant
, no attempt is made to handle exceptions that may be thrown when constructing or copying types. The state of a Maybe
or Either
after a failed copy constructor call is undefined.