Реализация 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';
}