Реализация boost:: необязательный в C++11

Я экспериментирую с реализацией Boost:: Optional, как структура данных, используя функции C++11. Вот что у меня так далеко:

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();
  }
};

Я использую функцию неограниченного объединения, чтобы создать правильно выровненное пространство для необязательного значения, которое может быть сохранено на месте вместо динамически выделяемого пространства. В основном все работает, за исключением случаев, когда я хочу создать вариант<> со ссылкой. Например maybe<int&> заставляет g++ 4.7 жаловаться:

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

Что я должен сделать, чтобы сделать, возможно, ссылки на магазин классов? Любые другие улучшения / предложения для класса также приветствуются.

2 ответа

Решение

Чтобы эта работа работала со ссылками, вам определенно нужна явная специализация, потому что вы не можете разместить новую ссылку: вам нужно использовать указатели для хранения.

Кроме того, в коде отсутствует оператор присваивания копии. Конструктор перемещения и оператор присваивания перемещения также подойдут (тем более что это причина № 1 для переопределения) boost::optional: тот, кто в толпе не хватает их).

Необязательные типы были предложены для C++14, но из-за некоторых угловых ситуаций вокруг поведения, не определенного в стандартах, он был отложен до C++17.

К счастью, проблема UB не должна иметь значения для большинства людей, потому что все основные компиляторы определяют ее правильно. Поэтому, если вы не используете старые компиляторы, вы можете просто вставить доступный код для реализации необязательного типа в вашем проекте (это всего лишь один заголовочный файл):

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

Тогда вы можете использовать это так:

#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';
}
Другие вопросы по тегам