diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2020-03-01 12:19:49 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2020-03-01 12:19:49 +0100 |
| commit | 1bd35044ee96e2bccb66749be5a48307c6e28218 (patch) | |
| tree | a2e1b4760713a20ae63c3a72ae47425a71e7053c /include | |
| parent | f00fb5779dcf2443b74d114093afbbd2441523ad (diff) | |
| parent | 8c5f53f0c3052cc30c2fe78feb1432b2a5c4e847 (diff) | |
| download | newtype-1bd35044ee96e2bccb66749be5a48307c6e28218.tar.xz newtype-1bd35044ee96e2bccb66749be5a48307c6e28218.zip | |
Diffstat (limited to 'include')
| -rw-r--r-- | include/newtype/derivable.hpp | 58 | ||||
| -rw-r--r-- | include/newtype/derivation_clause.hpp | 45 | ||||
| -rw-r--r-- | include/newtype/deriving.hpp | 3 | ||||
| -rw-r--r-- | include/newtype/impl/new_type_iterator_types.hpp | 66 | ||||
| -rw-r--r-- | include/newtype/impl/type_traits_extensions.hpp | 923 | ||||
| -rw-r--r-- | include/newtype/new_type.hpp | 527 | ||||
| -rw-r--r-- | include/newtype/version.hpp | 6 |
7 files changed, 674 insertions, 954 deletions
diff --git a/include/newtype/derivable.hpp b/include/newtype/derivable.hpp index 19c79d9..c798c59 100644 --- a/include/newtype/derivable.hpp +++ b/include/newtype/derivable.hpp @@ -12,73 +12,17 @@ namespace nt using tag_type = DerivableTag; }; - /** - * @brief A set of standard derivation tags - * - * This convenience namespace contains all standard derivation tags. - * - * @since 1.0.0 - */ inline namespace derivables { - /** - * @brief A tag to enable derivation of arithmetic operators - * - * @since 1.0.0 - */ auto constexpr Arithmetic = derivable<struct arithmetic_tag>{}; - - /** - * @brief A tag to enable derivation of "equality comparison with base type" operators - * - * @note Deriving this feature seriously weakens the using nt::new_type instance - * @since 1.0.0 - */ auto constexpr EqBase = derivable<struct eq_base_tag>{}; - - /** - * @brief A tag to enable derivation of a specialization of std::hash - * - * @since 1.0.0 - */ auto constexpr Hash = derivable<struct hash_tag>{}; - - /** - * @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" - * @since 1.0.0 - */ auto constexpr ImplicitConversion = derivable<struct implicit_conversion_tag>{}; - - /** - * @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 Iterable = derivable<struct iterable_tag>{}; auto constexpr Read = derivable<struct read_tag>{}; - - /** - * @brief A tag to enable derivation of the relational operators - * - * @since 1.0.0 - */ auto constexpr Relational = derivable<struct relational_tag>{}; - - /** - * @brief A tag to enable derivation of the stream output operator - * - * @since 1.0.0 - */ auto constexpr Show = derivable<struct show_tag>{}; } // namespace derivables diff --git a/include/newtype/derivation_clause.hpp b/include/newtype/derivation_clause.hpp index edb2f85..6de70e1 100644 --- a/include/newtype/derivation_clause.hpp +++ b/include/newtype/derivation_clause.hpp @@ -9,11 +9,6 @@ namespace nt { - /** - * A @p deriving clause type - * - * @tparam DerivableTags A list of tag types defining a set of derivable features - */ template<typename... DerivableTags> struct derivation_clause { @@ -21,88 +16,48 @@ namespace nt { } - /** - * Check whether the derivation clause contains a given derivable - */ template<typename DerivableTag> auto constexpr operator()(derivable<DerivableTag>) const noexcept -> bool { return (std::is_same_v<DerivableTags, DerivableTag> || ...); } - /** - * Check whether the derivation clause contains all derivables in a given lists - */ template<typename DerivableTag, typename... RemainingDerivableTags> auto constexpr operator()(derivable<DerivableTag>, derivable<RemainingDerivableTags>...) const noexcept -> bool { return (*this)(derivable<DerivableTag>{}) && (*this)(derivable<RemainingDerivableTags>{}...); } - /** - * Check whether this derivation clause is less than an other derivation clause - * - * A derivation clause is considered less than an other derivation clause iff. its set of derivables is a strict subset of - * the set derivables of the other. - */ template<typename... OtherDerivableTags> auto constexpr operator<(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool { return (sizeof...(DerivableTags) < sizeof...(OtherDerivableTags)) && other(derivable<DerivableTags>{}...); } - /** - * Check whether this derivation clause is greater than an other derivation clause - * - * A derivation clause is considered greater than an other derivation clause iff. its set of derivables is a strict superset - * of the set derivables of the other. - */ template<typename... OtherDerivableTags> auto constexpr operator>(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool { return other < *this; } - /** - * Check whether this derivation clause is equal to an other derivation clause - * - * Two derivation clauses are considered equal if both have the same set of derivables - */ template<typename... OtherDerivableTags> auto constexpr operator==(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool { return sizeof...(DerivableTags) == sizeof...(OtherDerivableTags) && other(derivable<DerivableTags>{}...); } - /** - * Check whether this derivation clause is not equal to an other derivation clause - * - * Two derivation clauses are considered not equal if neither has the same set of derivables as the other - */ template<typename... OtherDerivableTags> auto constexpr operator!=(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool { return !(*this == other); } - /** - * Check whether this derivation clause is less-than or equal to an other derivation clause - * - * @see nt::distinct::operator== - * @see nt::distinct::operator< - */ template<typename... OtherDerivableTags> auto constexpr operator<=(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool { return *this < other || *this == other; } - /** - * Check whether this derivation clause is greater-than or equal to an other derivation clause - * - * @see nt::distinct::operator== - * @see nt::distinct::operator< - */ template<typename... OtherDerivableTags> auto constexpr operator>=(derivation_clause<OtherDerivableTags...> other) const noexcept -> bool { diff --git a/include/newtype/deriving.hpp b/include/newtype/deriving.hpp index e762c9b..ae10bab 100644 --- a/include/newtype/deriving.hpp +++ b/include/newtype/deriving.hpp @@ -10,9 +10,6 @@ namespace nt { - /** - * Create a new derivation clause with the given derivables - */ template<typename... DerivableTags> auto constexpr deriving(derivable<DerivableTags>... features) noexcept -> derivation_clause<DerivableTags...> { diff --git a/include/newtype/impl/new_type_iterator_types.hpp b/include/newtype/impl/new_type_iterator_types.hpp new file mode 100644 index 0000000..2ea8274 --- /dev/null +++ b/include/newtype/impl/new_type_iterator_types.hpp @@ -0,0 +1,66 @@ +#ifndef NEWTYPE_IMPL_NEW_TYPE_ITERATOR_TYPES_HPP +#define NEWTYPE_IMPL_NEW_TYPE_ITERATOR_TYPES_HPP + +#include "newtype/version.hpp" + +#include <type_traits> + +namespace nt::impl +{ + + template<typename T, bool = false, typename = std::void_t<>> + struct new_type_iterator + { + }; + + template<typename T> + struct new_type_iterator<T, true, std::void_t<typename T::iterator>> + { + using iterator = typename T::iterator; + }; + + template<typename T, bool = false, typename = std::void_t<>> + struct new_type_const_iterator + { + }; + + template<typename T> + struct new_type_const_iterator<T, true, std::void_t<typename T::const_iterator>> + { + using const_iterator = typename T::const_iterator; + }; + + template<typename T, bool = false, typename = std::void_t<>> + struct new_type_reverse_iterator + { + }; + + template<typename T> + struct new_type_reverse_iterator<T, true, std::void_t<typename T::reverse_iterator>> + { + using reverse_iterator = typename T::reverse_iterator; + }; + + template<typename T, bool = false, typename = std::void_t<>> + struct new_type_const_reverse_iterator + { + }; + + template<typename T> + struct new_type_const_reverse_iterator<T, true, std::void_t<typename T::const_reverse_iterator>> + { + using const_reverse_iterator = typename T::const_reverse_iterator; + }; + + template<typename T, bool Enabled> + struct new_type_iterator_types + : new_type_iterator<T, Enabled> + , new_type_const_iterator<T, Enabled> + , new_type_reverse_iterator<T, Enabled> + , new_type_const_reverse_iterator<T, Enabled> + { + }; + +} // namespace nt::impl + +#endif
\ No newline at end of file diff --git a/include/newtype/impl/type_traits_extensions.hpp b/include/newtype/impl/type_traits_extensions.hpp index 1f46fb4..dc41649 100644 --- a/include/newtype/impl/type_traits_extensions.hpp +++ b/include/newtype/impl/type_traits_extensions.hpp @@ -14,125 +14,57 @@ namespace nt::impl inline namespace equality_comparable { - /** - * @brief A trait to test if a given type is comparable using operator== - * - * @tparam T The type to test - * @note This specialization forms the base case for non-equals-comparable T - */ template<typename T, typename = void> struct is_equality_comparable : std::false_type { }; - /** - * @brief A trait to test if a given type is comparable using operator== - * - * @tparam T The type to test - * @note This specialization forms the case for equals-comparable T - */ template<typename T> struct is_equality_comparable<T, std::void_t<decltype(std::declval<T const &>() == std::declval<T const &>())>> : std::true_type { }; - /** - * @brief A variable template to test if a given type is comparable using operator== - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_equality_comparable_v = is_equality_comparable<T>::value; - /** - * @brief A trait to test if a given type is noexcept comparable using operator== - * - * @tparam T The type to test - * @note This specialization forms the base case for non-noexcept equals-comparable or non-equals-comparable T - */ template<typename T, typename = void> struct is_nothrow_equality_comparable : std::false_type { }; - /** - * @brief A trait to test if a given type is noexcept comparable using operator== - * - * @tparam T The type to test - * @note This specialization forms the case for equals-comparable T detemining if T is noexcept comparable using operator== - */ template<typename T> struct is_nothrow_equality_comparable<T, std::void_t<decltype(std::declval<T const &>() == std::declval<T const &>())>> : std::bool_constant<noexcept(std::declval<T const &>() == std::declval<T const &>())> { }; - /** - * @brief A variable template to test if a given type is noexcept comparable using operator== - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_nothrow_equality_comparable_v = is_nothrow_equality_comparable<T>::value; - /** - * @brief A trait to test if a given type is comparable using operator!= - * - * @tparam T The type to test - * @note This specialization forms the base case for non-not-equals-comparable T - */ template<typename T, typename = void> struct is_inequality_comparable : std::false_type { }; - /** - * @brief A trait to test if a given type is comparable using operator!= - * - * @tparam T The type to test - * @note This specialization forms the case for not-equals-comparable T - */ template<typename T> struct is_inequality_comparable<T, std::void_t<decltype(std::declval<T const &>() != std::declval<T const &>())>> : std::true_type { }; - /** - * @brief A variable template to test if a given type is comparable using operator!= - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_inequality_comparable_v = is_inequality_comparable<T>::value; - /** - * @brief A trait to test if a given type is noexcept comparable using operator!= - * - * @tparam T The type to test - * @note This specialization forms the base case for non-noexcept not-equals-comparable or non-not-equals-comparable T - */ template<typename T, typename = void> struct is_nothrow_inequality_comparable : std::false_type { }; - /** - * @brief A trait to test if a given type is noexcept comparable using operator== - * - * @tparam T The type to test - * @note This specialization forms the case for equals-comparable T detemining if T is noexcept comparable using operator!= - */ template<typename T> struct is_nothrow_inequality_comparable<T, std::void_t<decltype(std::declval<T const &>() != std::declval<T const &>())>> : std::bool_constant<noexcept(std::declval<T const &>() != std::declval<T const &>())> { }; - /** - * @brief A variable template to test if a given type is noexcept comparable using operator!= - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_nothrow_inequality_comparable_v = is_nothrow_inequality_comparable<T>::value; @@ -141,250 +73,112 @@ namespace nt::impl inline namespace relationally_comparable { - /** - * @brief A trait to test if a given type is comparable using operator< - * - * @tparam T The type to test - * @note This specialization forms the base case for non-less-than-comparable T - */ template<typename T, typename = void> struct is_less_than_comparable : std::false_type { }; - /** - * @brief A trait to test if a given type is comparable using operator< - * - * @tparam T The type to test - * @note This specialization forms the case for less-than-comparable T - */ template<typename T> struct is_less_than_comparable<T, std::void_t<decltype(std::declval<T const &>() < std::declval<T const &>())>> : std::true_type { }; - /** - * @brief A variable template to test if a given type is comparable using operator< - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_less_than_comparable_v = is_less_than_comparable<T>::value; - /** - * @brief A trait to test if a given type is noexcept comparable using operator< - * - * @tparam T The type to test - * @note This specialization forms the base case for non-noexcept less-than-comparable or non-less-than-comparable T - */ template<typename T, typename = void> struct is_nothrow_less_than_comparable : std::false_type { }; - /** - * @brief A trait to test if a given type is noexcept comparable using operator< - * - * @tparam T The type to test - * @note This specialization forms the case for less-than-comparable T detemining if T is noexcept comparable using operator< - */ template<typename T> struct is_nothrow_less_than_comparable<T, std::void_t<decltype(std::declval<T const &>() < std::declval<T const &>())>> : std::bool_constant<noexcept(std::declval<T const &>() < std::declval<T const &>())> { }; - /** - * @brief A variable template to test if a given type is noexcept comparable using operator< - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_nothrow_less_than_comparable_v = is_nothrow_less_than_comparable<T>::value; - /** - * @brief A trait to test if a given type is comparable using operator> - * - * @tparam T The type to test - * @note This specialization forms the base case for non-greater-than-comparable T - */ template<typename T, typename = void> struct is_greater_than_comparable : std::false_type { }; - /** - * @brief A trait to test if a given type is comparable using operator> - * - * @tparam T The type to test - * @note This specialization forms the case for greater-than-comparable T - */ template<typename T> struct is_greater_than_comparable<T, std::void_t<decltype(std::declval<T const &>() > std::declval<T const &>())>> : std::true_type { }; - /** - * @brief A variable template to test if a given type is comparable using operator> - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_greater_than_comparable_v = is_greater_than_comparable<T>::value; - /** - * @brief A trait to test if a given type is noexcept comparable using operator> - * - * @tparam T The type to test - * @note This specialization forms the base case for non-noexcept greater-than-comparable or non-greater-than-comparable T - */ template<typename T, typename = void> struct is_nothrow_greater_than_comparable : std::false_type { }; - /** - * @brief A trait to test if a given type is noexcept comparable using operator> - * - * @tparam T The type to test - * @note This specialization forms the case for greater-than-comparable T detemining if T is noexcept comparable using operator> - */ template<typename T> struct is_nothrow_greater_than_comparable<T, std::void_t<decltype(std::declval<T const &>() > std::declval<T const &>())>> : std::bool_constant<noexcept(std::declval<T const &>() > std::declval<T const &>())> { }; - /** - * @brief A variable template to test if a given type is noexcept comparable using operator> - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_nothrow_greater_than_comparable_v = is_nothrow_greater_than_comparable<T>::value; - /** - * @brief A trait to test if a given type is comparable using operator<= - * - * @tparam T The type to test - * @note This specialization forms the base case for non-less-than-or-equal-to-comparable T - */ template<typename T, typename = void> struct is_less_than_equal_to_comparable : std::false_type { }; - /** - * @brief A trait to test if a given type is comparable using operator<= - * - * @tparam T The type to test - * @note This specialization forms the case for less-than-or-equal-to-comparable T - */ template<typename T> struct is_less_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() <= std::declval<T const &>())>> : std::true_type { }; - /** - * @brief A variable template to test if a given type is comparable using operator<= - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_less_than_equal_to_comparable_v = is_less_than_equal_to_comparable<T>::value; - /** - * @brief A trait to test if a given type is noexcept comparable using operator<= - * - * @tparam T The type to test - * @note This specialization forms the base case for non-noexcept less-than-or-equal-to-comparable or non-less-than-or-equal-to-comparable T - */ template<typename T, typename = void> struct is_nothrow_less_than_equal_to_comparable : std::false_type { }; - /** - * @brief A trait to test if a given type is noexcept comparable using operator<= - * - * @tparam T The type to test - * @note This specialization forms the case for less-than-or-equal-to-comparable T detemining if T is noexcept comparable using operator<= - */ template<typename T> struct is_nothrow_less_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() <= std::declval<T const &>())>> : std::bool_constant<noexcept(std::declval<T const &>() <= std::declval<T const &>())> { }; - /** - * @brief A variable template to test if a given type is noexcept comparable using operator<= - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_nothrow_less_than_equal_to_comparable_v = is_nothrow_less_than_equal_to_comparable<T>::value; - /** - * @brief A trait to test if a given type is comparable using operator>= - * - * @tparam T The type to test - * @note This specialization forms the base case for non-greater-than-or-equal-to-comparable T - */ template<typename T, typename = void> struct is_greater_than_equal_to_comparable : std::false_type { }; - /** - * @brief A trait to test if a given type is comparable using operator>= - * - * @tparam T The type to test - * @note This specialization forms the case for greater-than-or-equal-to-comparable T - */ template<typename T> struct is_greater_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() >= std::declval<T const &>())>> : std::true_type { }; - /** - * @brief A variable template to test if a given type is comparable using operator>= - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_greater_than_equal_to_comparable_v = is_greater_than_equal_to_comparable<T>::value; - /** - * @brief A trait to test if a given type is noexcept comparable using operator>= - * - * @tparam T The type to test - * @note This specialization forms the base case for non-noexcept greater-than-or-equal-to-comparable or - * non-greater-than-or-equal-to-comparable T - */ template<typename T, typename = void> struct is_nothrow_greater_than_equal_to_comparable : std::false_type { }; - /** - * @brief A trait to test if a given type is noexcept comparable using operator>= - * - * @tparam T The type to test - * @note This specialization forms the case for greater-than-or-equal-to-comparable T detemining if T is noexcept comparable using - * operator>= - */ template<typename T> struct is_nothrow_greater_than_equal_to_comparable<T, std::void_t<decltype(std::declval<T const &>() >= std::declval<T const &>())>> : std::bool_constant<noexcept(std::declval<T const &>() >= std::declval<T const &>())> { }; - /** - * @brief A variable template to test if a given type is noexcept comparable using operator>= - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_nothrow_greater_than_equal_to_comparable_v = is_nothrow_greater_than_equal_to_comparable<T>::value; } // namespace relationally_comparable @@ -392,126 +186,58 @@ namespace nt::impl inline namespace iostreamable { - /** - * @brief A trait to test if a given type is output streamable - * - * @tparam T The type to test - * @note This specialization forms the base case for non-output-streamable T - */ template<typename StreamType, typename T, typename = void> struct is_output_streamable : std::false_type { }; - /** - * @brief A trait to test if a given type is output streamable - * - * @tparam T The type to test - * @note This specialization forms the case for output-streamable T - */ template<typename StreamType, typename T> struct is_output_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() << std::declval<T const &>())>> : std::true_type { }; - /** - * @brief A variable template to test if a given type is output streamable - * - * @tparam T The type to test - */ template<typename StreamType, typename T> auto constexpr is_output_streamable_v = is_output_streamable<StreamType, T>::value; - /** - * @brief A trait to test if a given type is noexcept output streamable - * - * @tparam T The type to test - * @note This specialization forms the base case for non-noexcept output-streamable or non-output-streamable T - */ template<typename StreamType, typename T, typename = void> struct is_nothrow_output_streamable : std::false_type { }; - /** - * @brief A trait to test if a given type is noexcept output streamable - * - * @tparam T The type to test - * @note This specialization forms the case for output-streamable T detemining if T is noexcept output-streamable - */ template<typename StreamType, typename T> struct is_nothrow_output_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() << std::declval<T const &>())>> : std::bool_constant<noexcept(std::declval<StreamType &>() << std::declval<T const &>())> { }; - /** - * @brief A variable template to test if a given type is noexcept output streamable - * - * @tparam T The type to test - */ template<typename StreamType, typename T> auto constexpr is_nothrow_output_streamable_v = is_nothrow_output_streamable<StreamType, T>::value; - /** - * @brief A trait to test if a given type is input streamable - * - * @tparam T The type to test - * @note This specialization forms the base case for non-input-streamable T - */ template<typename StreamType, typename T, typename = void> struct is_input_streamable : std::false_type { }; - /** - * @brief A trait to test if a given type is input streamable - * - * @tparam T The type to test - * @note This specialization forms the case for input-streamable T - */ template<typename StreamType, typename T> struct is_input_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() >> std::declval<T &>())>> : std::true_type { }; - /** - * @brief A variable template to test if a given type is input streamable - * - * @tparam T The type to test - */ template<typename StreamType, typename T> auto constexpr is_input_streamable_v = is_input_streamable<StreamType, T>::value; - /** - * @brief A trait to test if a given type is noexcept input streamable - * - * @tparam T The type to test - * @note This specialization forms the base case for non-noexcept input-streamable or non-input-streamable T - */ template<typename StreamType, typename T, typename = void> struct is_nothrow_input_streamable : std::false_type { }; - /** - * @brief A trait to test if a given type is noexcept input streamable - * - * @tparam T The type to test - * @note This specialization forms the case for input-streamable T detemining if T is noexcept input-streamable - */ template<typename StreamType, typename T> struct is_nothrow_input_streamable<StreamType, T, std::void_t<decltype(std::declval<StreamType &>() >> std::declval<T &>())>> : std::bool_constant<noexcept(std::declval<StreamType &>() >> std::declval<T &>())> { }; - /** - * @brief A variable template to test if a given type is noexcept input streamable - * - * @tparam T The type to test - */ template<typename StreamType, typename T> auto constexpr is_nothrow_input_streamable_v = is_nothrow_input_streamable<StreamType, T>::value; @@ -520,247 +246,111 @@ namespace nt::impl inline namespace arithmetic { - /** - * @brief A trait to test if a given type is addable - * - * @tparam T The type to test - * @note This specialization forms the base case for non-addable T - */ template<typename T, typename = void> struct is_addable : std::false_type { }; - /** - * @brief A trait to test if a given type is addable - * - * @tparam T The type to test - * @note This specialization forms the case for addable T - */ template<typename T> struct is_addable<T, std::void_t<decltype(std::declval<T const &>() + std::declval<T const &>())>> : std::true_type { }; - /** - * @brief A variable template to test if a given type is addable - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_addable_v = is_addable<T>::value; - /** - * @brief A trait to test if a given type is noexcept addable - * - * @tparam T The type to test - * @note This specialization forms the base case for non-noexcept addable or non-addable T - */ template<typename T, typename = void> struct is_nothrow_addable : std::false_type { }; - /** - * @brief A trait to test if a given type is noexcept addable - * - * @tparam T The type to test - * @note This specialization forms the case for addable T detemining if T is noexcept addable - */ template<typename T> struct is_nothrow_addable<T, std::void_t<decltype(std::declval<T const &>() + std::declval<T const &>())>> : std::bool_constant<noexcept(std::declval<T const &>() + std::declval<T const &>())> { }; - /** - * @brief A variable template to test if a given type is noexcept addable - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_nothrow_addable_v = is_nothrow_addable<T>::value; - /** - * @brief A trait to test if a given type is subtractable - * - * @tparam T The type to test - * @note This specialization forms the base case for non-subtractable T - */ template<typename T, typename = void> struct is_subtractable : std::false_type { }; - /** - * @brief A trait to test if a given type is subtractable - * - * @tparam T The type to test - * @note This specialization forms the case for subtractable T - */ template<typename T> struct is_subtractable<T, std::void_t<decltype(std::declval<T const &>() - std::declval<T const &>())>> : std::true_type { }; - /** - * @brief A variable template to test if a given type is subtractable - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_subtractable_v = is_subtractable<T>::value; - /** - * @brief A trait to test if a given type is noexcept subtractable - * - * @tparam T The type to test - * @note This specialization forms the base case for non-noexcept subtractable or non-subtractable T - */ template<typename T, typename = void> struct is_nothrow_subtractable : std::false_type { }; - /** - * @brief A trait to test if a given type is noexcept subtractable - * - * @tparam T The type to test - * @note This specialization forms the case for subtractable T detemining if T is noexcept subtractable - */ template<typename T> struct is_nothrow_subtractable<T, std::void_t<decltype(std::declval<T const &>() - std::declval<T const &>())>> : std::bool_constant<noexcept(std::declval<T const &>() - std::declval<T const &>())> { }; - /** - * @brief A variable template to test if a given type is noexcept subtractable - * - * @tparam T The type to test - */ template<typename T> auto constexpr is_nothrow_subtractable_v = is_nothrow_subtractable<T>::value; - /** - * @brief A trait to test if a given type is multipliable - * - * @tparam T The type to test - * @note This specialization forms the base case for non-multipliable T - */ template<typename T, typename = void> struct is_multipliable : std::false_type { }; - /** - * @brief A trait to test if a given type is multipliable - * - * @tparam T The type to test - * @note This specialization forms the case for multipliable T - */ template<typename T> struct is_multipliable<T, std::void_t<decltype(std::declval<T const &>() * std::declval<T const &>())>> : std::true_type { }; - /** - * @brief A variable template to test if a given type is multipliable - * - * @tparam |
