forked from TartanLlama/optional
Get references compiling, initial tests
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include "optional.hpp"
|
#include "optional.hpp"
|
||||||
|
|
||||||
TEST_CASE("Assignment", "[assignment]") {
|
TEST_CASE("Assignment value", "[assignment.value]") {
|
||||||
tl::optional<int> o1 = 42;
|
tl::optional<int> o1 = 42;
|
||||||
tl::optional<int> o2 = 12;
|
tl::optional<int> o2 = 12;
|
||||||
tl::optional<int> o3;
|
tl::optional<int> o3;
|
||||||
@@ -32,3 +32,37 @@ TEST_CASE("Assignment", "[assignment]") {
|
|||||||
o1 = std::move(o4);
|
o1 = std::move(o4);
|
||||||
REQUIRE(*o1 == 42);
|
REQUIRE(*o1 == 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("Assignment reference", "[assignment.ref]") {
|
||||||
|
auto i = 42;
|
||||||
|
auto j = 12;
|
||||||
|
|
||||||
|
tl::optional<int&> o1 = i;
|
||||||
|
tl::optional<int&> o2 = j;
|
||||||
|
tl::optional<int&> o3;
|
||||||
|
|
||||||
|
o1 = o1;
|
||||||
|
REQUIRE(*o1 == 42);
|
||||||
|
REQUIRE(&*o1 == &i);
|
||||||
|
|
||||||
|
o1 = o2;
|
||||||
|
REQUIRE(*o1 == 12);
|
||||||
|
|
||||||
|
o1 = o3;
|
||||||
|
REQUIRE(!o1);
|
||||||
|
|
||||||
|
auto k = 42;
|
||||||
|
o1 = k;
|
||||||
|
REQUIRE(*o1 == 42);
|
||||||
|
REQUIRE(*o1 == i);
|
||||||
|
REQUIRE(*o1 == k);
|
||||||
|
REQUIRE(&*o1 != &i);
|
||||||
|
REQUIRE(&*o1 == &k);
|
||||||
|
|
||||||
|
o1 = tl::nullopt;
|
||||||
|
REQUIRE(!o1);
|
||||||
|
|
||||||
|
o1 = std::move(o2);
|
||||||
|
REQUIRE(*o1 == 12);
|
||||||
|
}
|
||||||
|
@@ -28,4 +28,23 @@ TEST_CASE("Constructors", "[constructors]") {
|
|||||||
|
|
||||||
tl::optional<int> o9 = std::move(o7);
|
tl::optional<int> o9 = std::move(o7);
|
||||||
REQUIRE(*o9 == 42);
|
REQUIRE(*o9 == 42);
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::optional<int &> o;
|
||||||
|
REQUIRE(!o);
|
||||||
|
|
||||||
|
tl::optional<int &> oo = o;
|
||||||
|
REQUIRE(!oo);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto i = 42;
|
||||||
|
tl::optional<int &> o = i;
|
||||||
|
REQUIRE(o);
|
||||||
|
REQUIRE(*o == 42);
|
||||||
|
|
||||||
|
tl::optional<int &> oo = o;
|
||||||
|
REQUIRE(oo);
|
||||||
|
REQUIRE(*oo == 42);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -37,4 +37,8 @@ TEST_CASE("Make optional", "[make_optional]") {
|
|||||||
REQUIRE(o5->v[1] == 1);
|
REQUIRE(o5->v[1] == 1);
|
||||||
REQUIRE(std::get<0>(o5->t) == 2);
|
REQUIRE(std::get<0>(o5->t) == 2);
|
||||||
REQUIRE(std::get<1>(o5->t) == 3);
|
REQUIRE(std::get<1>(o5->t) == 3);
|
||||||
|
|
||||||
|
auto i = 42;
|
||||||
|
auto o6 = tl::make_optional<int&>(i);
|
||||||
|
REQUIRE((std::is_same<decltype(o6), tl::optional<int&>>::value));
|
||||||
}
|
}
|
||||||
|
256
tl/optional.hpp
256
tl/optional.hpp
@@ -1573,10 +1573,18 @@ void swap(optional<T> &lhs,
|
|||||||
return lhs.swap(rhs);
|
return lhs.swap(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
namespace detail {
|
||||||
inline constexpr optional<detail::decay_t<T>> make_optional(T &&v) {
|
struct i_am_secret {};
|
||||||
return optional<detail::decay_t<T>>(std::forward<T>(v));
|
} // namespace detail
|
||||||
|
|
||||||
|
template <class T = detail::i_am_secret, class U,
|
||||||
|
class Ret =
|
||||||
|
detail::conditional_t<std::is_same<T, detail::i_am_secret>::value,
|
||||||
|
detail::decay_t<U>, T>>
|
||||||
|
inline constexpr optional<Ret> make_optional(U &&v) {
|
||||||
|
return optional<Ret>(std::forward<U>(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class... Args>
|
template <class T, class... Args>
|
||||||
inline constexpr optional<T> make_optional(Args &&... args) {
|
inline constexpr optional<T> make_optional(Args &&... args) {
|
||||||
return optional<T>(in_place, std::forward<Args>(args)...);
|
return optional<T>(in_place, std::forward<Args>(args)...);
|
||||||
@@ -2056,18 +2064,14 @@ public:
|
|||||||
/// \synopsis template <class U=T> constexpr optional(U &&u);
|
/// \synopsis template <class U=T> constexpr optional(U &&u);
|
||||||
template <
|
template <
|
||||||
class U = T,
|
class U = T,
|
||||||
detail::enable_if_t<std::is_convertible<U &&, T &>::value> * = nullptr,
|
detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>::value> * =
|
||||||
detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>> * = nullptr>
|
nullptr>
|
||||||
constexpr optional(U &&u) : m_value(std::addressof(u)) {}
|
constexpr optional(U &&u) : m_value(std::addressof(u)) {
|
||||||
|
static_assert(std::is_lvalue_reference<U>::value, "U must be an lvalue");
|
||||||
|
}
|
||||||
|
|
||||||
/// \exclude
|
/// \exclude
|
||||||
template <class U = T, detail::enable_if_t<
|
template <class U>
|
||||||
!std::is_convertible<U &, T &>::value> * = nullptr>
|
|
||||||
constexpr optional(U &&u) : base(in_place, std::forward<U>(u)) {}
|
|
||||||
|
|
||||||
/// \exclude
|
|
||||||
template <class U, detail::enable_if_t<
|
|
||||||
!std::is_convertible<const U &, T>::value> * = nullptr>
|
|
||||||
constexpr explicit optional(const optional<U> &rhs) : optional(*rhs) {}
|
constexpr explicit optional(const optional<U> &rhs) : optional(*rhs) {}
|
||||||
|
|
||||||
/// No-op
|
/// No-op
|
||||||
@@ -2091,9 +2095,10 @@ public:
|
|||||||
/// one.
|
/// one.
|
||||||
/// \synopsis optional &operator=(U &&u);
|
/// \synopsis optional &operator=(U &&u);
|
||||||
template <class U = T,
|
template <class U = T,
|
||||||
detail::enable_if<!detail::is_optional<detail::decay_t<U>>::value>
|
detail::enable_if_t<!detail::is_optional<detail::decay_t<U>>::value>
|
||||||
* = nullptr>
|
* = nullptr>
|
||||||
optional &operator=(U &&u) {
|
optional &operator=(U &&u) {
|
||||||
|
static_assert(std::is_lvalue_reference<U>::value, "U must be an lvalue");
|
||||||
m_value = std::addressof(u);
|
m_value = std::addressof(u);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -2103,8 +2108,7 @@ public:
|
|||||||
/// Copies the value from `rhs` if there is one. Otherwise resets the stored
|
/// Copies the value from `rhs` if there is one. Otherwise resets the stored
|
||||||
/// value in `*this`.
|
/// value in `*this`.
|
||||||
/// \synopsis optional &operator=(const optional<U> & rhs);
|
/// \synopsis optional &operator=(const optional<U> & rhs);
|
||||||
template <class U,
|
template <class U>
|
||||||
detail::enable_if<std::is_convertible<U &, T &>::value> * = nullptr>
|
|
||||||
optional &operator=(const optional<U> &rhs) {
|
optional &operator=(const optional<U> &rhs) {
|
||||||
m_value = std::addressof(rhs.value());
|
m_value = std::addressof(rhs.value());
|
||||||
return *this;
|
return *this;
|
||||||
@@ -2126,24 +2130,17 @@ public:
|
|||||||
/// If both have a value, the values are swapped.
|
/// If both have a value, the values are swapped.
|
||||||
/// If one has a value, it is moved to the other and the movee is left
|
/// If one has a value, it is moved to the other and the movee is left
|
||||||
/// valueless.
|
/// valueless.
|
||||||
void
|
void swap(optional &rhs) noexcept { std::swap(m_value, rhs.m_value); }
|
||||||
swap(optional &rhs) noexcept {
|
|
||||||
std::swap(m_value, rhs.m_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \returns a pointer to the stored value
|
/// \returns a pointer to the stored value
|
||||||
/// \requires a value is stored
|
/// \requires a value is stored
|
||||||
/// \group pointer
|
/// \group pointer
|
||||||
/// \synopsis constexpr const T *operator->() const;
|
/// \synopsis constexpr const T *operator->() const;
|
||||||
constexpr const T *operator->() const {
|
constexpr const T *operator->() const { return m_value; }
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \group pointer
|
/// \group pointer
|
||||||
/// \synopsis constexpr T *operator->();
|
/// \synopsis constexpr T *operator->();
|
||||||
TL_OPTIONAL_11_CONSTEXPR T *operator->() {
|
TL_OPTIONAL_11_CONSTEXPR T *operator->() { return m_value; }
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \returns the stored value
|
/// \returns the stored value
|
||||||
/// \requires a value is stored
|
/// \requires a value is stored
|
||||||
@@ -2156,9 +2153,7 @@ public:
|
|||||||
constexpr const T &operator*() const & { return *m_value; }
|
constexpr const T &operator*() const & { return *m_value; }
|
||||||
|
|
||||||
/// \exclude
|
/// \exclude
|
||||||
TL_OPTIONAL_11_CONSTEXPR T &&operator*() && {
|
TL_OPTIONAL_11_CONSTEXPR T &&operator*() && { return std::move(*m_value); }
|
||||||
return std::move(*m_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||||
/// \exclude
|
/// \exclude
|
||||||
@@ -2224,207 +2219,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Destroys the stored value if one exists, making the optional empty
|
/// Destroys the stored value if one exists, making the optional empty
|
||||||
void reset() noexcept {
|
void reset() noexcept { m_value = nullptr; }
|
||||||
m_value = nullptr;
|
|
||||||
}
|
private:
|
||||||
|
T *m_value;
|
||||||
}; // namespace tl
|
}; // namespace tl
|
||||||
|
|
||||||
/// \group relop
|
|
||||||
/// \brief Compares two optional objects
|
|
||||||
/// \details If both optionals contain a value, they are compared with `T`s
|
|
||||||
/// relational operators. Otherwise `lhs` and `rhs` are equal only if they are
|
|
||||||
/// both empty, and `lhs` is less than `rhs` only if `rhs` is empty and `lhs`
|
|
||||||
/// is not.
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator==(const optional<T> &lhs,
|
|
||||||
const optional<U> &rhs) {
|
|
||||||
return lhs.has_value() == rhs.has_value() &&
|
|
||||||
(!lhs.has_value() || *lhs == *rhs);
|
|
||||||
}
|
|
||||||
/// \group relop
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator!=(const optional<T> &lhs,
|
|
||||||
const optional<U> &rhs) {
|
|
||||||
return lhs.has_value() != rhs.has_value() ||
|
|
||||||
(lhs.has_value() && *lhs != *rhs);
|
|
||||||
}
|
|
||||||
/// \group relop
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator<(const optional<T> &lhs,
|
|
||||||
const optional<U> &rhs) {
|
|
||||||
return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs);
|
|
||||||
}
|
|
||||||
/// \group relop
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator>(const optional<T> &lhs,
|
|
||||||
const optional<U> &rhs) {
|
|
||||||
return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs);
|
|
||||||
}
|
|
||||||
/// \group relop
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator<=(const optional<T> &lhs,
|
|
||||||
const optional<U> &rhs) {
|
|
||||||
return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs);
|
|
||||||
}
|
|
||||||
/// \group relop
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator>=(const optional<T> &lhs,
|
|
||||||
const optional<U> &rhs) {
|
|
||||||
return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \group relop_nullopt
|
|
||||||
/// \brief Compares an optional to a `nullopt`
|
|
||||||
/// \details Equivalent to comparing the optional to an empty optional
|
|
||||||
template <class T>
|
|
||||||
inline constexpr bool operator==(const optional<T> &lhs, nullopt_t) noexcept {
|
|
||||||
return !lhs.has_value();
|
|
||||||
}
|
|
||||||
/// \group relop_nullopt
|
|
||||||
template <class T>
|
|
||||||
inline constexpr bool operator==(nullopt_t, const optional<T> &rhs) noexcept {
|
|
||||||
return !rhs.has_value();
|
|
||||||
}
|
|
||||||
/// \group relop_nullopt
|
|
||||||
template <class T>
|
|
||||||
inline constexpr bool operator!=(const optional<T> &lhs, nullopt_t) noexcept {
|
|
||||||
return lhs.has_value();
|
|
||||||
}
|
|
||||||
/// \group relop_nullopt
|
|
||||||
template <class T>
|
|
||||||
inline constexpr bool operator!=(nullopt_t, const optional<T> &rhs) noexcept {
|
|
||||||
return rhs.has_value();
|
|
||||||
}
|
|
||||||
/// \group relop_nullopt
|
|
||||||
template <class T>
|
|
||||||
inline constexpr bool operator<(const optional<T> &, nullopt_t) noexcept {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/// \group relop_nullopt
|
|
||||||
template <class T>
|
|
||||||
inline constexpr bool operator<(nullopt_t, const optional<T> &rhs) noexcept {
|
|
||||||
return rhs.has_value();
|
|
||||||
}
|
|
||||||
/// \group relop_nullopt
|
|
||||||
template <class T>
|
|
||||||
inline constexpr bool operator<=(const optional<T> &lhs, nullopt_t) noexcept {
|
|
||||||
return !lhs.has_value();
|
|
||||||
}
|
|
||||||
/// \group relop_nullopt
|
|
||||||
template <class T>
|
|
||||||
inline constexpr bool operator<=(nullopt_t, const optional<T> &) noexcept {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/// \group relop_nullopt
|
|
||||||
template <class T>
|
|
||||||
inline constexpr bool operator>(const optional<T> &lhs, nullopt_t) noexcept {
|
|
||||||
return lhs.has_value();
|
|
||||||
}
|
|
||||||
/// \group relop_nullopt
|
|
||||||
template <class T>
|
|
||||||
inline constexpr bool operator>(nullopt_t, const optional<T> &) noexcept {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/// \group relop_nullopt
|
|
||||||
template <class T>
|
|
||||||
inline constexpr bool operator>=(const optional<T> &, nullopt_t) noexcept {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/// \group relop_nullopt
|
|
||||||
template <class T>
|
|
||||||
inline constexpr bool operator>=(nullopt_t, const optional<T> &rhs) noexcept {
|
|
||||||
return !rhs.has_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \group relop_t
|
|
||||||
/// \brief Compares the optional with a value.
|
|
||||||
/// \details If the optional has a value, it is compared with the other value
|
|
||||||
/// using `T`s relational operators. Otherwise, the optional is considered
|
|
||||||
/// less than the value.
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator==(const optional<T> &lhs, const U &rhs) {
|
|
||||||
return lhs.has_value() ? *lhs == rhs : false;
|
|
||||||
}
|
|
||||||
/// \group relop_t
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator==(const U &lhs, const optional<T> &rhs) {
|
|
||||||
return rhs.has_value() ? lhs == *rhs : false;
|
|
||||||
}
|
|
||||||
/// \group relop_t
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator!=(const optional<T> &lhs, const U &rhs) {
|
|
||||||
return lhs.has_value() ? *lhs != rhs : true;
|
|
||||||
}
|
|
||||||
/// \group relop_t
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator!=(const U &lhs, const optional<T> &rhs) {
|
|
||||||
return rhs.has_value() ? lhs != *rhs : true;
|
|
||||||
}
|
|
||||||
/// \group relop_t
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator<(const optional<T> &lhs, const U &rhs) {
|
|
||||||
return lhs.has_value() ? *lhs < rhs : true;
|
|
||||||
}
|
|
||||||
/// \group relop_t
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator<(const U &lhs, const optional<T> &rhs) {
|
|
||||||
return rhs.has_value() ? lhs < *rhs : false;
|
|
||||||
}
|
|
||||||
/// \group relop_t
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator<=(const optional<T> &lhs, const U &rhs) {
|
|
||||||
return lhs.has_value() ? *lhs <= rhs : true;
|
|
||||||
}
|
|
||||||
/// \group relop_t
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator<=(const U &lhs, const optional<T> &rhs) {
|
|
||||||
return rhs.has_value() ? lhs <= *rhs : false;
|
|
||||||
}
|
|
||||||
/// \group relop_t
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator>(const optional<T> &lhs, const U &rhs) {
|
|
||||||
return lhs.has_value() ? *lhs > rhs : false;
|
|
||||||
}
|
|
||||||
/// \group relop_t
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator>(const U &lhs, const optional<T> &rhs) {
|
|
||||||
return rhs.has_value() ? lhs > *rhs : true;
|
|
||||||
}
|
|
||||||
/// \group relop_t
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator>=(const optional<T> &lhs, const U &rhs) {
|
|
||||||
return lhs.has_value() ? *lhs >= rhs : false;
|
|
||||||
}
|
|
||||||
/// \group relop_t
|
|
||||||
template <class T, class U>
|
|
||||||
inline constexpr bool operator>=(const U &lhs, const optional<T> &rhs) {
|
|
||||||
return rhs.has_value() ? lhs >= *rhs : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \synopsis template <class T>\nvoid swap(optional<T> &lhs, optional<T>
|
|
||||||
/// &rhs);
|
|
||||||
template <class T,
|
|
||||||
detail::enable_if_t<std::is_move_constructible<T>::value> * = nullptr,
|
|
||||||
detail::enable_if_t<detail::is_swappable<T>::value> * = nullptr>
|
|
||||||
void swap(optional<T> &lhs,
|
|
||||||
optional<T> &rhs) noexcept(noexcept(lhs.swap(rhs))) {
|
|
||||||
return lhs.swap(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline constexpr optional<detail::decay_t<T>> make_optional(T &&v) {
|
|
||||||
return optional<detail::decay_t<T>>(std::forward<T>(v));
|
|
||||||
}
|
|
||||||
template <class T, class... Args>
|
|
||||||
inline constexpr optional<T> make_optional(Args &&... args) {
|
|
||||||
return optional<T>(in_place, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
template <class T, class U, class... Args>
|
|
||||||
inline constexpr optional<T> make_optional(std::initializer_list<U> il,
|
|
||||||
Args &&... args) {
|
|
||||||
return optional<T>(in_place, il, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \exclude
|
/// \exclude
|
||||||
namespace detail {
|
namespace detail {
|
||||||
#ifdef TL_OPTIONAL_CX14
|
#ifdef TL_OPTIONAL_CX14
|
||||||
|
Reference in New Issue
Block a user