diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2019-12-29 15:08:44 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2019-12-29 15:08:44 +0100 |
| commit | a8d181abe5a64def14b0f90f6149a67cca354a3a (patch) | |
| tree | 736d0c20701571ff62c0d2901f3a7f92a6f97b9a | |
| parent | a501b37531c6b87195592009777918c3b38cc9e2 (diff) | |
| download | newtype-a8d181abe5a64def14b0f90f6149a67cca354a3a.tar.xz newtype-a8d181abe5a64def14b0f90f6149a67cca354a3a.zip | |
new_type: cleanup implementation
| -rw-r--r-- | include/newtype/derivable.hpp | 21 | ||||
| -rw-r--r-- | include/newtype/impl/new_type_storage.hpp | 152 | ||||
| -rw-r--r-- | include/newtype/new_type.hpp | 375 |
3 files changed, 343 insertions, 205 deletions
diff --git a/include/newtype/derivable.hpp b/include/newtype/derivable.hpp index 157bac7..1b6651f 100644 --- a/include/newtype/derivable.hpp +++ b/include/newtype/derivable.hpp @@ -10,7 +10,7 @@ namespace nt using derivable = type<NameTag>; /** - * A set of standard derivation tags + * @brief A set of standard derivation tags * * This convenience namespace contains all standard derivation tags. * @@ -20,21 +20,21 @@ namespace nt { /** - * A tag to enable derivation of arithmetic operators + * @brief A tag to enable derivation of arithmetic operators * * @since 1.0.0 */ auto constexpr Arithmetic = derivable<struct arithmetic_tag>{}; /** - * A tag to enable derivation of equality comparison operators + * @brief A tag to enable derivation of equality comparison operators * * @since 1.0.0 */ auto constexpr EqBase = derivable<struct eq_tag>{}; /** - * A tag to enable derivation of the implicit "conversion to base type" operator + * @brief A tag to enable derivation of the implicit "conversion to base type" operator * * @note If this tag is not present in the derivation clause of any given nt::new_type, the type instance only supports explicit * "conversion to base type" @@ -43,21 +43,28 @@ namespace nt auto constexpr ImplicitConversion = derivable<struct implicit_conversion_tag>{}; /** - * A tag to enable derivation of the stream input operator + * @brief A tag to enable access to the members of the base type object through a pointer + * + * @since 1.0.0 + */ + auto constexpr Indirection = derivable<struct indirection_tag>{}; + + /** + * @brief A tag to enable derivation of the stream input operator * * @since 1.0.0 */ auto constexpr Read = derivable<struct read_tag>{}; /** - * A tag to enable derivation of the relational operators + * @brief A tag to enable derivation of the relational operators * * @since 1.0.0 */ auto constexpr Relational = derivable<struct relational_tag>{}; /** - * A tag to enable derivation of the stream output operator + * @brief A tag to enable derivation of the stream output operator * * @since 1.0.0 */ diff --git a/include/newtype/impl/new_type_storage.hpp b/include/newtype/impl/new_type_storage.hpp new file mode 100644 index 0000000..414eff4 --- /dev/null +++ b/include/newtype/impl/new_type_storage.hpp @@ -0,0 +1,152 @@ +#ifndef NEWTYPE_IMPL_NEW_TYPE_STORAGE_HPP +#define NEWTYPE_IMPL_NEW_TYPE_STORAGE_HPP + +#include <type_traits> + +namespace nt::impl +{ + + template<typename BaseType, typename TagType> + struct new_type_storage + { + constexpr new_type_storage() noexcept(std::is_nothrow_default_constructible_v<BaseType>) + : m_value{} + { + } + + template<typename ArgumentType> + constexpr explicit new_type_storage(ArgumentType && value) noexcept(std::is_nothrow_constructible_v<BaseType, ArgumentType>) + : m_value{std::forward<ArgumentType>(value)} + { + } + + BaseType m_value; + }; + + template<typename BaseType, typename TagType, bool = std::is_default_constructible_v<BaseType>> + struct new_type_constructor : new_type_storage<BaseType, TagType> + { + using super = new_type_storage<BaseType, TagType>; + using super::super; + + constexpr new_type_constructor(BaseType const & value) + : super{value} + { + } + + constexpr new_type_constructor(BaseType && value) + : super{std::move(value)} + { + } + }; + + template<typename BaseType, typename TagType> + struct new_type_constructor<BaseType, TagType, false> : new_type_storage<BaseType, TagType> + { + using super = new_type_storage<BaseType, TagType>; + using super::super; + + constexpr new_type_constructor() = delete; + + constexpr new_type_constructor(BaseType const & value) + : super{value} + { + } + + constexpr new_type_constructor(BaseType && value) + : super{std::move(value)} + { + } + }; + + template<typename BaseType, typename TagType, bool = std::is_copy_constructible_v<BaseType>> + struct new_type_copy_constructor : new_type_constructor<BaseType, TagType> + { + using new_type_constructor<BaseType, TagType>::new_type_constructor; + + constexpr new_type_copy_constructor(new_type_copy_constructor const &) = default; + constexpr new_type_copy_constructor(new_type_copy_constructor &&) = default; + auto constexpr operator=(new_type_copy_constructor &) -> new_type_copy_constructor & = default; + auto constexpr operator=(new_type_copy_constructor &&) -> new_type_copy_constructor & = default; + }; + + template<typename BaseType, typename TagType> + struct new_type_copy_constructor<BaseType, TagType, false> : new_type_constructor<BaseType, TagType> + { + using new_type_constructor<BaseType, TagType>::new_type_constructor; + + constexpr new_type_copy_constructor(new_type_copy_constructor const &) = delete; + constexpr new_type_copy_constructor(new_type_copy_constructor &&) = default; + auto constexpr operator=(new_type_copy_constructor &) -> new_type_copy_constructor & = default; + auto constexpr operator=(new_type_copy_constructor &&) -> new_type_copy_constructor & = default; + }; + + template<typename BaseType, typename TagType, bool = std::is_move_constructible_v<BaseType>> + struct new_type_move_constructor : new_type_copy_constructor<BaseType, TagType> + { + using new_type_copy_constructor<BaseType, TagType>::new_type_copy_constructor; + + constexpr new_type_move_constructor(new_type_move_constructor const &) = default; + constexpr new_type_move_constructor(new_type_move_constructor &&) = default; + auto constexpr operator=(new_type_move_constructor &) -> new_type_move_constructor & = default; + auto constexpr operator=(new_type_move_constructor &&) -> new_type_move_constructor & = default; + }; + + template<typename BaseType, typename TagType> + struct new_type_move_constructor<BaseType, TagType, false> : new_type_copy_constructor<BaseType, TagType> + { + using new_type_copy_constructor<BaseType, TagType>::new_type_copy_constructor; + + constexpr new_type_move_constructor(new_type_move_constructor const &) = default; + constexpr new_type_move_constructor(new_type_move_constructor &&) = delete; + auto constexpr operator=(new_type_move_constructor &) -> new_type_move_constructor & = default; + auto constexpr operator=(new_type_move_constructor &&) -> new_type_move_constructor & = default; + }; + + template<typename BaseType, typename TagType, bool = std::is_copy_assignable_v<BaseType>> + struct new_type_copy_assignment : new_type_move_constructor<BaseType, TagType> + { + using new_type_move_constructor<BaseType, TagType>::new_type_move_constructor; + + constexpr new_type_copy_assignment(new_type_copy_assignment const &) = default; + constexpr new_type_copy_assignment(new_type_copy_assignment &&) = default; + auto constexpr operator=(new_type_copy_assignment &) -> new_type_copy_assignment & = default; + auto constexpr operator=(new_type_copy_assignment &&) -> new_type_copy_assignment & = default; + }; + + template<typename BaseType, typename TagType> + struct new_type_copy_assignment<BaseType, TagType, false> : new_type_move_constructor<BaseType, TagType> + { + using new_type_move_constructor<BaseType, TagType>::new_type_move_constructor; + + constexpr new_type_copy_assignment(new_type_copy_assignment const &) = default; + constexpr new_type_copy_assignment(new_type_copy_assignment &&) = default; + auto constexpr operator=(new_type_copy_assignment &) -> new_type_copy_assignment & = default; + auto constexpr operator=(new_type_copy_assignment &&) -> new_type_copy_assignment & = delete; + }; + + template<typename BaseType, typename TagType, bool = std::is_move_assignable_v<BaseType>> + struct new_type_move_assignment : new_type_copy_assignment<BaseType, TagType> + { + using new_type_copy_assignment<BaseType, TagType>::new_type_copy_assignment; + + constexpr new_type_move_assignment(new_type_move_assignment const &) = default; + constexpr new_type_move_assignment(new_type_move_assignment &&) = default; + auto constexpr operator=(new_type_move_assignment &) -> new_type_move_assignment & = default; + auto constexpr operator=(new_type_move_assignment &&) -> new_type_move_assignment & = default; + }; + + template<typename BaseType, typename TagType> + struct new_type_move_assignment<BaseType, TagType, false> : new_type_copy_assignment<BaseType, TagType> + { + using new_type_copy_assignment<BaseType, TagType>::new_type_copy_assignment; + + constexpr new_type_move_assignment(new_type_move_assignment const &) = default; + constexpr new_type_move_assignment(new_type_move_assignment &&) = default; + auto constexpr operator=(new_type_move_assignment &) -> new_type_move_assignment & = default; + auto constexpr operator=(new_type_move_assignment &&) -> new_type_move_assignment & = delete; + }; + +} // namespace nt::impl + +#endif diff --git a/include/newtype/new_type.hpp b/include/newtype/new_type.hpp index 57674cb..7f73daa 100644 --- a/include/newtype/new_type.hpp +++ b/include/newtype/new_type.hpp @@ -3,6 +3,7 @@ #include "newtype/derivable.hpp" #include "newtype/deriving.hpp" +#include "newtype/impl/new_type_storage.hpp" #include "newtype/type.hpp" #include <istream> @@ -12,131 +13,9 @@ namespace nt { - namespace impl - { - - template<typename BaseType, typename TagType> - struct new_type_storage - { - constexpr new_type_storage() noexcept(std::is_nothrow_default_constructible_v<BaseType>) - : m_value{} - { - } - - template<typename ArgumentType> - constexpr explicit new_type_storage(ArgumentType && value) noexcept(std::is_nothrow_constructible_v<BaseType, ArgumentType>) - : m_value{std::forward<ArgumentType>(value)} - { - } - - BaseType m_value; - }; - - template<typename BaseType, typename TagType, bool = std::is_default_constructible_v<BaseType>> - struct new_type_constructor : new_type_storage<BaseType, TagType> - { - using new_type_storage<BaseType, TagType>::new_type_storage; - }; - - template<typename BaseType, typename TagType> - struct new_type_constructor<BaseType, TagType, false> : new_type_storage<BaseType, TagType> - { - using new_type_storage<BaseType, TagType>::new_type_storage; - - new_type_constructor() = delete; - }; - - template<typename BaseType, typename TagType, bool = std::is_copy_constructible_v<BaseType>> - struct new_type_copy_constructor : new_type_constructor<BaseType, TagType> - { - using new_type_constructor<BaseType, TagType>::new_type_constructor; - - constexpr new_type_copy_constructor(new_type_copy_constructor const &) = default; - constexpr new_type_copy_constructor(new_type_copy_constructor &&) = default; - auto constexpr operator=(new_type_copy_constructor &) -> new_type_copy_constructor & = default; - auto constexpr operator=(new_type_copy_constructor &&) -> new_type_copy_constructor & = default; - }; - - template<typename BaseType, typename TagType> - struct new_type_copy_constructor<BaseType, TagType, false> : new_type_constructor<BaseType, TagType> - { - using new_type_constructor<BaseType, TagType>::new_type_constructor; - - constexpr new_type_copy_constructor(new_type_copy_constructor const &) = delete; - constexpr new_type_copy_constructor(new_type_copy_constructor &&) = default; - auto constexpr operator=(new_type_copy_constructor &) -> new_type_copy_constructor & = default; - auto constexpr operator=(new_type_copy_constructor &&) -> new_type_copy_constructor & = default; - }; - - template<typename BaseType, typename TagType, bool = std::is_move_constructible_v<BaseType>> - struct new_type_move_constructor : new_type_copy_constructor<BaseType, TagType> - { - using new_type_copy_constructor<BaseType, TagType>::new_type_copy_constructor; - - constexpr new_type_move_constructor(new_type_move_constructor const &) = default; - constexpr new_type_move_constructor(new_type_move_constructor &&) = default; - auto constexpr operator=(new_type_move_constructor &) -> new_type_move_constructor & = default; - auto constexpr operator=(new_type_move_constructor &&) -> new_type_move_constructor & = default; - }; - - template<typename BaseType, typename TagType> - struct new_type_move_constructor<BaseType, TagType, false> : new_type_copy_constructor<BaseType, TagType> - { - using new_type_copy_constructor<BaseType, TagType>::new_type_copy_constructor; - - constexpr new_type_move_constructor(new_type_move_constructor const &) = default; - constexpr new_type_move_constructor(new_type_move_constructor &&) = delete; - auto constexpr operator=(new_type_move_constructor &) -> new_type_move_constructor & = default; - auto constexpr operator=(new_type_move_constructor &&) -> new_type_move_constructor & = default; - }; - - template<typename BaseType, typename TagType, bool = std::is_copy_assignable_v<BaseType>> - struct new_type_copy_assignment : new_type_move_constructor<BaseType, TagType> - { - using new_type_move_constructor<BaseType, TagType>::new_type_move_constructor; - - constexpr new_type_copy_assignment(new_type_copy_assignment const &) = default; - constexpr new_type_copy_assignment(new_type_copy_assignment &&) = default; - auto constexpr operator=(new_type_copy_assignment &) -> new_type_copy_assignment & = default; - auto constexpr operator=(new_type_copy_assignment &&) -> new_type_copy_assignment & = default; - }; - - template<typename BaseType, typename TagType> - struct new_type_copy_assignment<BaseType, TagType, false> : new_type_move_constructor<BaseType, TagType> - { - using new_type_move_constructor<BaseType, TagType>::new_type_move_constructor; - - constexpr new_type_copy_assignment(new_type_copy_assignment const &) = default; - constexpr new_type_copy_assignment(new_type_copy_assignment &&) = default; - auto constexpr operator=(new_type_copy_assignment &) -> new_type_copy_assignment & = default; - auto constexpr operator=(new_type_copy_assignment &&) -> new_type_copy_assignment & = delete; - }; - - template<typename BaseType, typename TagType, bool = std::is_move_assignable_v<BaseType>> - struct new_type_move_assignment : new_type_copy_assignment<BaseType, TagType> - { - using new_type_copy_assignment<BaseType, TagType>::new_type_copy_assignment; - - constexpr new_type_move_assignment(new_type_move_assignment const &) = default; - constexpr new_type_move_assignment(new_type_move_assignment &&) = default; - auto constexpr operator=(new_type_move_assignment &) -> new_type_move_assignment & = default; - auto constexpr operator=(new_type_move_assignment &&) -> new_type_move_assignment & = default; - }; - - template<typename BaseType, typename TagType> - struct new_type_move_assignment<BaseType, TagType, false> : new_type_copy_assignment<BaseType, TagType> - { - using new_type_copy_assignment<BaseType, TagType>::new_type_copy_assignment; - - constexpr new_type_move_assignment(new_type_move_assignment const &) = default; - constexpr new_type_move_assignment(new_type_move_assignment &&) = default; - auto constexpr operator=(new_type_move_assignment &) -> new_type_move_assignment & = default; - auto constexpr operator=(new_type_move_assignment &&) -> new_type_move_assignment & = delete; - }; - - } // namespace impl - /** + * @brief Create a new type based on an existing one + * * The class template nt::new_type is designed to allow the creation of new types based on existing types. Similarly to the Haskell newtype, * this class template creates a new type that is layout equivalent to the underlying type. * @@ -147,71 +26,108 @@ namespace nt template<typename BaseType, typename TagType, auto DerivationClause = deriving()> class new_type : impl::new_type_move_assignment<BaseType, TagType> { - using super = impl::new_type_move_assignment<BaseType, TagType>; + static_assert(!std::is_reference_v<BaseType>, "The base type must not be a reference type"); + static_assert(!std::is_void_v<std::remove_cv_t<BaseType>>, "The base type must not be possibly cv-qualified void"); + + template<typename BaseTypeT, typename TagTypeT, auto DerivationClauseV, typename CharType, typename StreamTraits> + auto friend + operator>>(std::basic_istream<CharType, StreamTraits> & input, new_type<BaseTypeT, TagTypeT, DerivationClauseV> & target) noexcept( + noexcept(std::declval<std::basic_istream<CharType, StreamTraits> &>() >> std::declval<BaseTypeT &>())) + -> std::enable_if_t<DerivationClauseV(nt::Read), std::basic_istream<CharType, StreamTraits>> &; - template<typename BaseTypeT, - typename TagTypeT, - auto DerivationClauseV, - typename CharType, - typename StreamTraits, - typename Enablement, - typename StreamType> - auto friend operator>>(std::basic_istream<CharType, StreamTraits> & input, - new_type<BaseTypeT, TagTypeT, DerivationClauseV> & target) noexcept(noexcept(std::declval<StreamType &>() >> - std::declval<BaseTypeT &>())) - -> std::basic_istream<CharType, StreamTraits> &; + using super = impl::new_type_move_assignment<BaseType, TagType>; public: /** - * The base type of this nt::new_type + * @brief The base type of this nt::new_type + * + * This type alias provides convenient access to the contained objects type */ using base_type = BaseType; /** - * The tag type of this nt::new_type + * @brief The tag type of this nt::new_type + * + * This type alias provides convenient access to the tag type of this nt::new_type instance */ using tag_type = TagType; /** - * The type of the derivation clause of this nt::newtype + * @brief The type of the derivation clause of this nt::newtype + * + * This type alias provides convenient access to the type of the derivation clause of this nt::new_type instance */ using derivation_clause_type = decltype(DerivationClause); /** - * The derivation clause fo this nt::new_type + * @brief The derivation clause fo this nt::new_type + * + * This static data-member provides conevient access to the derivation clause of this nt::new_type instance */ auto constexpr static derivation_clause = DerivationClause; + using super::super; + + /** + * @brief Construct an instance of this nt::new_type by default initializing the contained object + * + * @note This constructor is available iff. the base type is default-constructible. Otherwise is is defined as deleted. + * @throw This constructor throws any exception thrown the base type constructor. It is noexcept iff. the base type constructor is noexcept + */ constexpr new_type() noexcept(std::is_nothrow_default_constructible_v<BaseType>) = default; + /** + * @brief Copy-construct an instance of this nt::new_type from an existing one + * + * @note This constructor is available iff. the base type is copy-constructible. Otherwise is is defined as deleted. + * @throw This constructor throws any exception thrown the base type copy-constructor. It is noexcept iff. the base type copy-constructor + * is noexcept + */ constexpr new_type(new_type const &) noexcept(std::is_nothrow_copy_constructible_v<BaseType>) = default; + /** + * @brief Move-construct an instance of this nt::new_type from an existing one + * + * @note This constructor is available iff. the base type is move-constructible. Otherwise is is defined as deleted. + * @throw This constructor throws any exception thrown the base type move-constructor. It is noexcept iff. the base types move-constructor + * is noexcept + */ constexpr new_type(new_type &&) noexcept(std::is_nothrow_move_constructible_v<BaseType>) = default; - constexpr explicit new_type(BaseType const & value) noexcept(std::is_nothrow_copy_constructible_v<BaseType>) - : super{value} - { - } - - constexpr explicit new_type(BaseType const && value) noexcept(std::is_nothrow_move_constructible_v<BaseType>) - : super{std::move(value)} - { - } - + /** + * @brief Copy-assign the value of an existing instance of this nt::new_type to this instance + * + * @note This assignment operator is available iff. the base type is copy-assignable. Otherwise it is defined as deleted. + * @throw This assignment operator throws any exception thrown by the base type copy-assignment operator. It is noexcept iff. the base type + * copy-assignment operator is noexcept. + * @return A reference to this instance + */ auto constexpr operator=(new_type const &) noexcept(std::is_nothrow_copy_assignable_v<BaseType>) -> new_type & = default; + /** + * @brief Move-assign the value of an existing instance of this nt::new_type to this instance + * + * @note This assignment operator is available iff. the base type is move-assignable. Otherwise it is defined as deleted. + * @throw This assignment operator throws any exception thrown by the base type move-assignment operator. It is noexcept iff. the base type + * move-assignment operator is noexcept. + * @return A reference to this instance + */ auto constexpr operator=(new_type &&) noexcept(std::is_nothrow_move_assignable_v<BaseType>) -> new_type & = default; + /** + * @brief Obtain a copy of the contained base type object + * + * @return BaseType + */ auto constexpr decay() const noexcept(std::is_nothrow_copy_constructible_v<BaseType>) -> BaseType { return this->m_value; } /** - * Convert this instance into the equivalent base type value + * @brief Convert this instance into the equivalent base type value * - * @note This overload participates only in overload resolution if the derivation clause of this @p new_type contains - * nt::ImplicitConversion + * @note This is only available if the derivation clause of this nt::new_type contains nt::ImplicitConversion */ template<typename NewType = new_type, std::enable_if_t<NewType::derivation_clause(nt::ImplicitConversion)> * = nullptr> constexpr operator base_type() const noexcept(std::is_nothrow_copy_constructible_v<base_type>) @@ -220,20 +136,45 @@ namespace nt } /** - * Convert this instance into the equivalent base type value + * @brief Convert this instance into the equivalent base type value * - * @note This overload participates only in overload resolution if the derivation clause of this @p new_type does not contain - * nt::ImplicitConversion + * @note This overload is only avalaible if the derivation clause of this nt::new_type does not contain nt::ImplicitConversion */ template<typename NewType = new_type, std::enable_if_t<!NewType::derivation_clause(nt::ImplicitConversion)> * = nullptr> explicit constexpr operator base_type() const noexcept(std::is_nothrow_copy_constructible_v<base_type>) { return decay(); } + + /** + * @brief Perform an access to a member of the base type + * + * @return A pointer to the contained base type object + */ + template<typename NewType = new_type> + auto constexpr operator-> () noexcept -> std::enable_if_t<NewType::derivation_clause(nt::Indirection), BaseType *> + { + return std::addressof(this->m_value); + } + + /** + * @brief Perform an access to a member of the base type + * + * @return A pointer to the contained base type object + */ + template<typename NewType = new_type> + auto constexpr operator-> () const noexcept -> std::enable_if_t<NewType::derivation_clause(nt::Indirection), BaseType const *> + { + return std::addressof(this->m_value); + } }; /** - * Compare two objects for equality + * @brief Compare two objects for equality + * + * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type + * comparison operator is noexcept. + * @return true iff. the base type comparison operator returns true, false otherwise. */ template<typename BaseType, typename TagType, auto DerivationClause> auto constexpr operator==(new_type<BaseType, TagType, DerivationClause> const & lhs, @@ -245,7 +186,11 @@ namespace nt } /** - * Compare two objects for non-equality + * @brief Compare two objects for non-equality + * + * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type + * comparison operator is noexcept. + * @return true iff. the base type comparison operator returns true, false otherwise. */ template<typename BaseType, typename TagType, auto DerivationClause> auto constexpr operator!=(new_type<BaseType, TagType, DerivationClause> const & lhs, @@ -257,93 +202,127 @@ namespace nt } /** - * Check if one nt::new_type object is less-than an other + * @brief Check if one nt::new_type object is less-than an other * - * @note This overload participates only in overload resolution if the derivation clause of this @p new_type does contain - * nt::Relational - * @return true iff. the object contained by lhs is less-than the one contained by rhs + * @note This operator is only avalaible if the the derivation clause of this nt::new_type does contains nt::Relational. Otherwise is is + * defined as deleted. + * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type + * comparison operator is noexcept. + * @return true iff. the base type comparison operator returns true, false otherwise. */ - template<typename BaseType, typename TagType, auto DerivationClause, typename = std::enable_if_t<DerivationClause(nt::Relational)>> + template<typename BaseType, typename TagType, auto DerivationClause> auto constexpr operator<(new_type<BaseType, TagType, DerivationClause> const & lhs, new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() < std::declval<BaseType const &>())) - -> bool + -> std::enable_if_t<DerivationClause(nt::Relational), bool> { return lhs.decay() < rhs.decay(); } + template<typename BaseType, typename TagType, auto DerivationClause> + auto constexpr operator<(new_type<BaseType, TagType, DerivationClause> const & lhs, + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() < + std::declval<BaseType const &>())) + -> std::enable_if_t<!DerivationClause(nt::Relational), bool> = delete; + /** * Check if one nt::new_type object is greater-than an other * - * @note This overload participates only in overload resolution if the derivation clause of this @p new_type does contain - * nt::Relational - * @return true iff. the object contained by lhs is greater-than the one contained by rhs + * @note This operator is only avalaible if the the derivation clause of this nt::new_type does contains nt::Relational. Otherwise is is + * defined as deleted. + * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type + * comparison operator is noexcept. + * @return true iff. the base type comparison operator returns true, false otherwise. */ - template<typename BaseType, typename TagType, auto DerivationClause, typename = std::enable_if_t<DerivationClause(nt::Relational)>> + template<typename BaseType, typename TagType, auto DerivationClause> auto constexpr operator>(new_type<BaseType, TagType, DerivationClause> const & lhs, new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() > std::declval<BaseType const &>())) - -> bool + -> std::enable_if_t<DerivationClause(nt::Relational), bool> { return lhs.decay() > rhs.decay(); } + template<typename BaseType, typename TagType, auto DerivationClause> + auto constexpr operator>(new_type<BaseType, TagType, DerivationClause> const & lhs, + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() > + std::declval<BaseType const &>())) + -> std::enable_if_t<!DerivationClause(nt::Relational), bool> = delete; + /** * Check if one nt::new_type object is less-than or equal-to an other * - * @note This overload participates only in overload resolution if the derivation clause of this @p new_type does contain - * nt::Relational - * @return true iff. the object contained by lhs is less-than or equal-to the one contained by rhs + * @note This operator is only avalaible if the the derivation clause of this nt::new_type does contains nt::Relational + * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type + * comparison operator is noexcept. + * @return true iff. the base type comparison operator returns true, false otherwise. */ - template<typename BaseType, typename TagType, auto DerivationClause, typename = std::enable_if_t<DerivationClause(nt::Relational)>> + template<typename BaseType, typename TagType, auto DerivationClause> auto constexpr operator<=(new_type<BaseType, TagType, DerivationClause> const & lhs, new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() <= std::declval<BaseType const &>())) - -> bool + -> std::enable_if_t<DerivationClause(nt::Relational), bool> { return lhs.decay() <= rhs.decay(); } + template<typename BaseType, typename TagType, auto DerivationClause> + auto constexpr operator<=(new_type<BaseType, TagType, DerivationClause> const & lhs, + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() <= + std::declval<BaseType const &>())) + -> std::enable_if_t<!DerivationClause(nt::Relational), bool> = delete; + /** * Check if one nt::new_type object is greater-than or equal-to an other * - * @note This overload participates only in overload resolution if the derivation clause of this @p new_type does contain - * nt::Relational - * @return true iff. the object contained by lhs is greater-than or equal-to the one contained by rhs + * @note This operator is only avalaible if the the derivation clause of this nt::new_type does contains nt::Relational + * @throw This comparison operator throws any exception thrown by the base type comparison operator. It it noexcept iff. the base type + * comparison operator is noexcept. + * @return true iff. the base type comparison operator returns true, false otherwise. */ - template<typename BaseType, typename TagType, auto DerivationClause, typename = std::enable_if_t<DerivationClause(nt::Relational)>> + template<typename BaseType, typename TagType, auto DerivationClause> auto constexpr operator>=(new_type<BaseType, TagType, DerivationClause> const & lhs, new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() >= std::declval<BaseType const &>())) - -> bool + -> std::enable_if_t<DerivationClause(nt::Relational), bool> { return lhs.decay() >= rhs.decay(); } - template<typename BaseType, - typename TagType, - auto DerivationClause, - typename CharType, - typename StreamTraits, - typename = std::enable_if_t<DerivationClause(nt::Show)>, - typename StreamType = std::basic_ostream<CharType, StreamTraits>> - auto operator<<(std::basic_ostream<CharType, StreamTraits> & output, - new_type<BaseType, TagType, DerivationClause> const & source) noexcept(noexcept(std::declval<StreamType &>() - << std::declval<BaseType const &>())) - -> std::basic_ostream<CharType, StreamTraits> & + template<typename BaseType, typename TagType, auto DerivationClause> + auto constexpr operator>=(new_type<BaseType, TagType, DerivationClause> const & lhs, + new_type<BaseType, TagType, DerivationClause> const & rhs) noexcept(noexcept(std::declval<BaseType const &>() >= + std::declval<BaseType const &>())) + -> std::enable_if_t<!DerivationClause(nt::Relational), bool> = delete; + + /** + * @brief Write the contained base type object to a standard output stream + * + * @note This operator is only available if the derivation clause of the passed in nt::new_type object contains nt::Show. + * @param output The output stream to write to + * @param source An instance of an nt::new_type that shall be written to the stream + * @return The a reference to the output stream + */ + template<typename BaseType, typename TagType, auto DerivationClause, typename CharType, typename StreamTraits> + auto operator<<(std::basic_ostream<CharType, StreamTraits> & output, new_type<BaseType, TagType, DerivationClause> const & source) noexcept( + noexcept(std::declval<std::basic_ostream<CharType, StreamTraits> &>() << std::declval<BaseType const &>())) + -> std::enable_if_t<DerivationClause(nt::Show), std::basic_ostream<CharType, StreamTraits>> & { return output << source.decay(); } - template<typename BaseType, - typename TagType, - auto DerivationClause, - typename CharType, - typename StreamTraits, - typename = std::enable_if_t<DerivationClause(nt::Read)>, - typename StreamType = std::basic_istream<CharType, StreamTraits>> + /** + * @brief Read an object of the base type from a standard input stream + * + * @note This operator is only available if the derivation clause of the passed in nt::new_type object contains nt::Read. + * @param output The input stream to read from + * @param source An instance of an nt::new_type that shall be read from the stream + * @return The a reference to the input stream + */ + template<typename BaseType, typename TagType, auto DerivationClause, typename CharType, typename StreamTraits> auto operator>>(std::basic_istream<CharType, StreamTraits> & input, new_type<BaseType, TagType, DerivationClause> & target) noexcept( - noexcept(std::declval<StreamType &>() >> std::declval<BaseType &>())) -> std::basic_istream<CharType, StreamTraits> & + noexcept(std::declval<std::basic_istream<CharType, StreamTraits> &>() >> std::declval<BaseType &>())) + -> std::enable_if_t<DerivationClause(nt::Read), std::basic_istream<CharType, StreamTraits>> & { return input >> target.m_value; } |
