8

I am experimenting with implementing boost::optional like data structure using c++11 features. Here is what I have so far :

template<typename T>
struct maybe {
  bool valid;

  union {
    T value;
  };

  maybe() : valid(false) {}
  maybe(const T& _v) {
  valid = true;
    new (&value) T(_v);
  }
  maybe(const maybe& other) {
    if (other.valid) {
      valid = true;
      new (&value) T(other.value);
    }
    else valid = false;
  }

  ~maybe() {
     if (valid)
       value.~T();
  }

  bool is_valid() { return valid; }

  operator T&() {
    if (valid) return value;
    throw std::bad_exception();
  }
};

I make use of the unrestricted union feature to create a properly aligned space for the optional value that can be stored in-situ, instead of dynamically allocation space. Things work mostly, except when I want to create a maybe<> with a reference. For instance maybe<int&> causes g++ 4.7 to complain :

error: ‘maybe<int&>::<anonymous union>::value’ may not have reference type ‘int&’
because it is a member of a union

What should I do to make the maybe class store references? Any other improvements/suggestions to the class are also welcome.

2 Answers 2

8

To make this work with references you definitely need an explicit specialization, because you can't do placement new of a reference: you need to use pointers for storage.

Beyond that, the code is missing a copy assignment operator. A move constructor, and move assignment operator would also be nice (especially since that's the #1 reason to reimplement boost::optional: the one in boost is lacking them).

Sign up to request clarification or add additional context in comments.

9 Comments

"That makes your class not working with non-default constructible types" This is not true, though. The standard seems to indicate that automatic initialization and destruction are suppressed for members of unions.
BTW, alignas(T) char data[sizeof(T)] seems more C++11-ish than what you have.
@keveman it's probably how aligned_storage is implemented. I find aligned_storage a lot more explicit about its business.
@rmartinho To each, his own. The committee painstakingly moved the aligned_storage idiom to the language proper, so I don't feel like using a library wrapper over the language feature.
@keveman regarding the default constructibility, that's quite interesting. Could you please refer me to the appropriate standard sections?
|
4

The optional types were proposed for C++14 but due to some corner cases around behavior undefined in standards it got postponed to C++17.

Fortunately, the UB issue shouldn't matter to most people because all major compilers do define it correctly. So unless you are using old compilers, you can actually just drop in the code available to implement optional type in your project (it's just one header file):

https://raw.githubusercontent.com/akrzemi1/Optional/master/optional.hpp

Then you can use it like this:

#if (defined __cplusplus) && (__cplusplus >= 201700L)
#include <optional>
#else
#include "optional.hpp"
#endif

#include <iostream>

#if (defined __cplusplus) && (__cplusplus >= 201700L)
using std::optional;
#else
using std::experimental::optional;
#endif

int main()
{
    optional<int> o1,      // empty
                  o2 = 1,  // init from rvalue
                  o3 = o2; // copy-constructor

    if (!o1) {
        cout << "o1 has no value";
    } 

    std::cout << *o2 << ' ' << *o3 << ' ' << *o4 << '\n';
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.