/** * @file

Emulating std::experimental::optional

*/
#define C++03

Why?

Straightforward motivation for extending types with some special values was interaction with PostgreSQL database full of NULL-able values. Correspondence between PostgreSQL and C++ is obvious as is the pattern:

Another source of interest are data optionally set in some interface (be it user interface or interface of some code layer). However helpful in case of code interface default values are they are not always sufficient (partly because of C++ identified-by-order parameters).

Similar to what?

std::experimental::optional<Type> looks like a treat but doesn't do much for those stuck with C++03. Actual inspiration came from in-house-made analog to it. Preexisting solution was all right but required that Type is default constructible. Regarding my hatred for evil default constructors (i. e. those breaking abstract type invariants) I had to see if this type requirement was really that necessary. I also wanted to avoid the obvious solution via dynamic memory - going to heap and emulating special value by NULL pointer somehow doesn't feel right.

How?

Idea is fairly simple - by leveraging boost::function which is DefaultConstructible Optional wrapper type can hold a "value provider" instead of value itself. Probably the only obstacle is inability to point function pointer to a constructor in C++ but trivial template workaround is sufficient.

This solution has a rather fine detail I initially hadn't even realized and had to be pointed to - in unfortunate case you are working with type whose constructor has side-effects mind the time of actual constructor call. The wrapper is lazy and the call is made in get_value() implementation. (Corner case but might bite you pretty badly.)

Snippet below is rather showing a way how to avoid DefaultConstructible requirement than a full emulation of std::experimental::optional interface.

You will find implementation comments in tooltips when you hover cursor over such code.

optional.hpp

#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <stdexcept>


template<typename T> class Optional {
    private:
        bool isnull_;
        boost::function<T()> value_provider_;

        template<typename T_> static T_ indirect_ctor_call(const T_& init) {
            return T_(init);
        }

    public:

        Optional()
        :   isnull_(true),
            value_provider_()
        {}

        Optional(const T& _value)
        :   isnull_(false),
            value_provider_(boost::bind(&indirect_ctor_call<T>, _value))
        { }

        Optional& operator=(const T& _value) {
            value_provider_ = boost::bind(&indirect_ctor_call<T>, _value);
            isnull_ = false;

            return *this;
        }

        bool isnull() const {
            return isnull_;
        }

        T get_value() const {
            if (isnull()) {
                throw std::logic_error("value is null");
            }

            return value_provider_();
        }
};