Don't derive nlohmann::optional from std::optional

This commit is contained in:
Alexander Karzhenkov 2022-07-03 13:15:35 +05:00
parent 57f0f502cb
commit 3854934101
5 changed files with 374 additions and 54 deletions

View File

@ -59,7 +59,7 @@ void from_json(const BasicJsonType& j, std::optional<T>& opt)
}
template<typename BasicJsonType, typename T>
void from_json(const BasicJsonType& j, nlohmann::optional<T>& opt)
void from_json(const BasicJsonType& j, optional<T>& opt)
{
if (j.is_null())
{

View File

@ -275,6 +275,13 @@ void to_json(BasicJsonType& j, const std::optional<T>& opt) noexcept
j = nullptr;
}
}
template<typename BasicJsonType, typename T,
enable_if_t<std::is_constructible<BasicJsonType, T>::value, int> = 0>
void to_json(BasicJsonType& j, const optional<T>& opt) noexcept
{
to_json(j, opt.base());
}
#endif
template<typename BasicJsonType, typename T,

View File

@ -7,15 +7,15 @@
#include <optional>
#include <utility>
namespace nlohmann
{
NLOHMANN_JSON_NAMESPACE_BEGIN
template <typename T>
class optional : public std::optional<T>
class optional
{
// *INDENT-OFF*
using base_type = std::optional<T>;
using value_type = T;
template <typename U, typename = optional>
struct has_conversion_operator : std::false_type { };
@ -67,17 +67,29 @@ class optional : public std::optional<T>
struct noexcept_fix_t {};
base_type base_value;
public:
const base_type& base() const
base_type& base() &
{
return *this;
return base_value;
}
const base_type& base() const &
{
return base_value;
}
base_type&& base() &&
{
return std::move(base_value);
}
constexpr optional() noexcept(noexcept(std::optional<noexcept_fix_t>())) = default;
constexpr optional(std::nullopt_t /* unused */) noexcept
: base_type(std::nullopt)
: base_value(std::nullopt)
{
}
@ -86,7 +98,7 @@ class optional : public std::optional<T>
noexcept(noexcept(
base_type(std::forward<U>(value).operator optional())
)) :
base_type(std::forward<U>(value).operator optional())
base_value(std::forward<U>(value).operator optional())
{
}
@ -95,7 +107,7 @@ class optional : public std::optional<T>
noexcept(noexcept(
base_type(std::forward<U>(value))
)) :
base_type(std::forward<U>(value))
base_value(std::forward<U>(value))
{
}
@ -105,7 +117,7 @@ class optional : public std::optional<T>
noexcept(noexcept(
base_type(std::forward<U>(value))
)) :
base_type(std::forward<U>(value))
base_value(std::forward<U>(value))
{
}
@ -115,7 +127,7 @@ class optional : public std::optional<T>
noexcept(noexcept(
base_type(std::in_place, std::forward<U>(u), std::forward<Args>(args)...)
)) :
base_type(std::in_place, std::forward<U>(u), std::forward<Args>(args)...)
base_value(std::in_place, std::forward<U>(u), std::forward<Args>(args)...)
{
}
@ -125,49 +137,190 @@ class optional : public std::optional<T>
noexcept(noexcept(
base_type(std::in_place, u, std::forward<Args>(args)...)
)) :
base_type(std::in_place, u, std::forward<Args>(args)...)
base_value(std::in_place, u, std::forward<Args>(args)...)
{
}
constexpr T& operator *() & noexcept { return *base_value; }
constexpr const T& operator *() const& noexcept { return *base_value; }
constexpr T&& operator *() && noexcept { return static_cast<T&&>(*base_value); }
constexpr const T&& operator *() const&& noexcept { return static_cast<const T&&>(*base_value); }
constexpr T* operator ->() noexcept { return base_value.operator ->(); }
constexpr const T* operator ->() const noexcept { return base_value.operator ->(); }
operator base_type& () & { return base_value; }
operator base_type&& () && { return std::move(base_value); }
// *INDENT-ON*
};
template<class T, class U>
constexpr bool operator == (const optional<T>& lhs, const optional<U>& rhs)
namespace detail::opt
{
return lhs.base() == rhs.base();
template <typename T> const T& cmp_val(const T& v)
{
return v;
}
template <typename T> const std::optional<T>& cmp_val(const optional<T>& v)
{
return v.base();
}
template <typename T> void cmp_val(const std::optional<T>& v) = delete;
} // namespace detail::opt
#ifdef JSON_HAS_CPP_20
template <typename T, typename U>
auto operator == (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs);
}
// *INDENT-OFF*
template <typename T, typename U>
auto operator <=> (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) <=> detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) <=> detail::opt::cmp_val(rhs);
}
// *INDENT-ON*
#else // JSON_HAS_CPP_20
template<class T, class U>
constexpr auto operator == (const optional<T>& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator == (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator == (const T& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs);
}
template<class T, class U>
constexpr bool operator != (const optional<T>& lhs, const optional<U>& rhs)
constexpr auto operator != (const optional<T>& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs))
{
return lhs.base() != rhs.base();
return detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator != (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator != (const T& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs);
}
template<class T, class U>
constexpr bool operator < (const optional<T>& lhs, const optional<U>& rhs)
constexpr auto operator < (const optional<T>& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs))
{
return lhs.base() < rhs.base();
return detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator < (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator < (const T& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs);
}
template<class T, class U>
constexpr bool operator <= (const optional<T>& lhs, const optional<U>& rhs)
constexpr auto operator <= (const optional<T>& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs))
{
return lhs.base() <= rhs.base();
return detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator <= (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator <= (const T& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs);
}
template<class T, class U>
constexpr bool operator > (const optional<T>& lhs, const optional<U>& rhs)
constexpr auto operator > (const optional<T>& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs))
{
return lhs.base() > rhs.base();
return detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator > (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator > (const T& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs);
}
template<class T, class U>
constexpr bool operator >= (const optional<T>& lhs, const optional<U>& rhs)
constexpr auto operator >= (const optional<T>& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs))
{
return lhs.base() >= rhs.base();
return detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs);
}
} // namespace nlohmann
template <class T, class U>
constexpr auto operator >= (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator >= (const T& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs);
}
#endif // JSON_HAS_CPP_20
NLOHMANN_JSON_NAMESPACE_END
#endif // JSON_HAS_CPP_17

View File

@ -4599,15 +4599,15 @@ NLOHMANN_JSON_NAMESPACE_END
#include <optional>
#include <utility>
namespace nlohmann
{
NLOHMANN_JSON_NAMESPACE_BEGIN
template <typename T>
class optional : public std::optional<T>
class optional
{
// *INDENT-OFF*
using base_type = std::optional<T>;
using value_type = T;
template <typename U, typename = optional>
struct has_conversion_operator : std::false_type { };
@ -4659,17 +4659,29 @@ class optional : public std::optional<T>
struct noexcept_fix_t {};
base_type base_value;
public:
const base_type& base() const
base_type& base() &
{
return *this;
return base_value;
}
const base_type& base() const &
{
return base_value;
}
base_type&& base() &&
{
return std::move(base_value);
}
constexpr optional() noexcept(noexcept(std::optional<noexcept_fix_t>())) = default;
constexpr optional(std::nullopt_t /* unused */) noexcept
: base_type(std::nullopt)
: base_value(std::nullopt)
{
}
@ -4678,7 +4690,7 @@ class optional : public std::optional<T>
noexcept(noexcept(
base_type(std::forward<U>(value).operator optional())
)) :
base_type(std::forward<U>(value).operator optional())
base_value(std::forward<U>(value).operator optional())
{
}
@ -4687,7 +4699,7 @@ class optional : public std::optional<T>
noexcept(noexcept(
base_type(std::forward<U>(value))
)) :
base_type(std::forward<U>(value))
base_value(std::forward<U>(value))
{
}
@ -4697,7 +4709,7 @@ class optional : public std::optional<T>
noexcept(noexcept(
base_type(std::forward<U>(value))
)) :
base_type(std::forward<U>(value))
base_value(std::forward<U>(value))
{
}
@ -4707,7 +4719,7 @@ class optional : public std::optional<T>
noexcept(noexcept(
base_type(std::in_place, std::forward<U>(u), std::forward<Args>(args)...)
)) :
base_type(std::in_place, std::forward<U>(u), std::forward<Args>(args)...)
base_value(std::in_place, std::forward<U>(u), std::forward<Args>(args)...)
{
}
@ -4717,50 +4729,191 @@ class optional : public std::optional<T>
noexcept(noexcept(
base_type(std::in_place, u, std::forward<Args>(args)...)
)) :
base_type(std::in_place, u, std::forward<Args>(args)...)
base_value(std::in_place, u, std::forward<Args>(args)...)
{
}
constexpr T& operator *() & noexcept { return *base_value; }
constexpr const T& operator *() const& noexcept { return *base_value; }
constexpr T&& operator *() && noexcept { return static_cast<T&&>(*base_value); }
constexpr const T&& operator *() const&& noexcept { return static_cast<const T&&>(*base_value); }
constexpr T* operator ->() noexcept { return base_value.operator ->(); }
constexpr const T* operator ->() const noexcept { return base_value.operator ->(); }
operator base_type& () & { return base_value; }
operator base_type&& () && { return std::move(base_value); }
// *INDENT-ON*
};
template<class T, class U>
constexpr bool operator == (const optional<T>& lhs, const optional<U>& rhs)
namespace detail::opt
{
return lhs.base() == rhs.base();
template <typename T> const T& cmp_val(const T& v)
{
return v;
}
template <typename T> const std::optional<T>& cmp_val(const optional<T>& v)
{
return v.base();
}
template <typename T> void cmp_val(const std::optional<T>& v) = delete;
} // namespace detail::opt
#ifdef JSON_HAS_CPP_20
template <typename T, typename U>
auto operator == (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs);
}
// *INDENT-OFF*
template <typename T, typename U>
auto operator <=> (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) <=> detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) <=> detail::opt::cmp_val(rhs);
}
// *INDENT-ON*
#else // JSON_HAS_CPP_20
template<class T, class U>
constexpr auto operator == (const optional<T>& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator == (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator == (const T& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) == detail::opt::cmp_val(rhs);
}
template<class T, class U>
constexpr bool operator != (const optional<T>& lhs, const optional<U>& rhs)
constexpr auto operator != (const optional<T>& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs))
{
return lhs.base() != rhs.base();
return detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator != (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator != (const T& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) != detail::opt::cmp_val(rhs);
}
template<class T, class U>
constexpr bool operator < (const optional<T>& lhs, const optional<U>& rhs)
constexpr auto operator < (const optional<T>& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs))
{
return lhs.base() < rhs.base();
return detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator < (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator < (const T& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) < detail::opt::cmp_val(rhs);
}
template<class T, class U>
constexpr bool operator <= (const optional<T>& lhs, const optional<U>& rhs)
constexpr auto operator <= (const optional<T>& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs))
{
return lhs.base() <= rhs.base();
return detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator <= (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator <= (const T& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) <= detail::opt::cmp_val(rhs);
}
template<class T, class U>
constexpr bool operator > (const optional<T>& lhs, const optional<U>& rhs)
constexpr auto operator > (const optional<T>& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs))
{
return lhs.base() > rhs.base();
return detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator > (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator > (const T& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) > detail::opt::cmp_val(rhs);
}
template<class T, class U>
constexpr bool operator >= (const optional<T>& lhs, const optional<U>& rhs)
constexpr auto operator >= (const optional<T>& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs))
{
return lhs.base() >= rhs.base();
return detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs);
}
} // namespace nlohmann
template <class T, class U>
constexpr auto operator >= (const optional<T>& lhs, const U& rhs) ->
decltype(detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs);
}
template <class T, class U>
constexpr auto operator >= (const T& lhs, const optional<U>& rhs) ->
decltype(detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs))
{
return detail::opt::cmp_val(lhs) >= detail::opt::cmp_val(rhs);
}
#endif // JSON_HAS_CPP_20
NLOHMANN_JSON_NAMESPACE_END
#endif // JSON_HAS_CPP_17
@ -4794,7 +4947,7 @@ void from_json(const BasicJsonType& j, std::optional<T>& opt)
}
template<typename BasicJsonType, typename T>
void from_json(const BasicJsonType& j, nlohmann::optional<T>& opt)
void from_json(const BasicJsonType& j, optional<T>& opt)
{
if (j.is_null())
{
@ -5790,6 +5943,13 @@ void to_json(BasicJsonType& j, const std::optional<T>& opt) noexcept
j = nullptr;
}
}
template<typename BasicJsonType, typename T,
enable_if_t<std::is_constructible<BasicJsonType, T>::value, int> = 0>
void to_json(BasicJsonType& j, const optional<T>& opt) noexcept
{
to_json(j, opt.base());
}
#endif
template<typename BasicJsonType, typename T,

View File

@ -113,12 +113,12 @@ TEST_CASE("nlohmann::optional copy")
{
opt1 = std::as_const(opt2);
CHECK(*opt1 == 222);
CHECK(*opt_int(std::as_const(opt1)) == 222);
CHECK(*opt_int(std::as_const(opt1).base()) == 222);
}
SECTION("2")
{
opt2 = std::as_const(opt1);
opt2 = std::as_const(opt1).base();
CHECK(*opt2 == 111);
CHECK(*opt_int(std::as_const(opt2)) == 111);
}