Question

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.

Était-ce utile?

La solution

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).

Autres conseils

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';
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top