aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.vscode/c_cpp_properties.json3
-rw-r--r--.vscode/settings.json5
-rw-r--r--conanfile.py4
-rw-r--r--source/doc/CMakeLists.txt8
-rw-r--r--source/doc/src/index.rst39
-rw-r--r--source/examples/CMakeLists.txt17
-rw-r--r--source/lib/include/newtype/newtype.hpp845
-rw-r--r--source/tests/src/threeway_comparison.cpp2
8 files changed, 372 insertions, 551 deletions
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
index eeb9f71..2091cd3 100644
--- a/.vscode/c_cpp_properties.json
+++ b/.vscode/c_cpp_properties.json
@@ -9,8 +9,7 @@
"compilerPath": "/usr/bin/g++",
"cppStandard": "c++20",
"intelliSenseMode": "gcc-x64",
- "configurationProvider": "ms-vscode.cmake-tools",
- "compileCommands": "${workspaceFolder}/build/compile_commands.json"
+ "configurationProvider": "ms-vscode.cmake-tools"
}
],
"version": 4
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 8db3e08..72ff434 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,9 +1,8 @@
{
// CMake Configuration
- "cmake.configureOnOpen": false,
+ "cmake.configureOnOpen": true,
"cmake.useCMakePresets": "always",
"cmake.sourceDirectory": "${workspaceFolder}/source",
- "cmake.skipConfigureIfCachePresent": true,
// C++ Configuration
"[cpp]": {
@@ -11,7 +10,7 @@
},
"C_Cpp.autoAddFileAssociations": false,
"C_Cpp.intelliSenseEngine": "default",
- "C_Cpp.errorSquiggles": "enabledIfIncludesResolve",
+ "C_Cpp.errorSquiggles": "enabled",
"C_Cpp.autocomplete": "default",
// RST Configuration
diff --git a/conanfile.py b/conanfile.py
index 4616c8a..222ac72 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -37,8 +37,8 @@ class NewtypeConan(ConanFile):
def build_requirements(self):
self.tool_requires("cmake/[>3.25]")
- self.tool_requires("ninja/[~1.11]")
- self.test_requires("catch2/[~3.3]")
+ self.tool_requires("ninja/[>1.11]")
+ self.test_requires("catch2/[>3.3]")
def generate(self):
toolchain = CMakeToolchain(self, generator="Ninja Multi-Config")
diff --git a/source/doc/CMakeLists.txt b/source/doc/CMakeLists.txt
index 616b040..7a9e27d 100644
--- a/source/doc/CMakeLists.txt
+++ b/source/doc/CMakeLists.txt
@@ -44,9 +44,10 @@ add_custom_target("docs"
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/html/index.html"
COMMAND "${DOCENV_DIR}/bin/sphinx-build"
+ "-q"
"-b"
"singlehtml"
- "-q"
+ "-E"
"${CMAKE_CURRENT_SOURCE_DIR}/src"
"${CMAKE_CURRENT_BINARY_DIR}/html"
DEPENDS ${SOURCES}
@@ -56,9 +57,10 @@ add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/html/index.html"
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/man/newtype.3"
COMMAND "${DOCENV_DIR}/bin/sphinx-build"
+ "-q"
"-b"
"man"
- "-q"
+ "-E"
"${CMAKE_CURRENT_SOURCE_DIR}/src"
"${CMAKE_CURRENT_BINARY_DIR}/man"
DEPENDS ${SOURCES}
@@ -66,7 +68,7 @@ add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/man/newtype.3"
COMMENT "Compiling man page"
)
-install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html"
+install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/singlehtml"
TYPE DOC
PATTERN ".doctrees" EXCLUDE
PATTERN ".buildinfo" EXCLUDE
diff --git a/source/doc/src/index.rst b/source/doc/src/index.rst
index 290f17e..88925aa 100644
--- a/source/doc/src/index.rst
+++ b/source/doc/src/index.rst
@@ -22,8 +22,8 @@ Example Usage
All examples shown in this section can be found in the directory :literal:`examples/src` within the source root.
-:ref:`new-type-usage-basic` below demonstrates the basic usage of :cpp:class:`new_type`.
-In it, :cpp:class:`new_type` is used to create thre new strong aliases :literal:`Width`, :literal:`Height`, and :literal:`Area` that all alias :literal:`unsigned int`.
+:ref:`new-type-usage-basic` below illustrates the basic usage of :cpp:class:`new_type`.
+In it, :cpp:class:`new_type` is used to create three new strong aliases :literal:`Width`, :literal:`Height`, and :literal:`Area`, all aliasing :literal:`unsigned int`.
.. literalinclude:: ../../examples/src/basic_usage.cpp
:language: c++
@@ -31,22 +31,22 @@ In it, :cpp:class:`new_type` is used to create thre new strong aliases :literal:
:name: new-type-usage-basic
:caption: Basic usage of :cpp:class:`new_type`
-However, using :cpp:class:`new_type` in this fashion seem quite cumbersome.
+However, using :cpp:class:`new_type` in this fashion is quite cumbersome.
Starting from the bottom, :literal:`unsigned int` can normally be shifted on to any :cpp:class:`std::basic_ostream`, like :cpp:var:`std::cout` in this example.
-Since printing values, among other things, is a common scenario, ``newtype`` provides facilities to support automatic derivation of supporting functions.
+Since printing values, among others, is a common use case, ``newtype`` provides facilities to support automatic derivation of supporting functions.
.. literalinclude:: ../../examples/src/basic_usage_with_show.cpp
- :emphasize-lines: 1,2,9
+ :emphasize-lines: 7,38
:language: c++
:linenos:
:name: new-type-usage-basic-show
:caption: Improved usability using the :cpp:var:`Show` derivation tag
-:ref:`new-type-usage-basic-show` demonstrates how the function template :cpp:func:`deriving` can be used to enable automatic derivation of the stream output operator for :literal:`Area`.
+:ref:`new-type-usage-basic-show` illustrates how the function template :cpp:func:`deriving` can be used to enable automatic derivation of the stream output operator for :literal:`Area`.
Similarly, it is possible to derive the stream input operators of :literal:`Width` and :literal:`Height`, as shown in :ref:`new-type-usage-basic-read` below.
.. literalinclude:: ../../examples/src/basic_usage_with_read.cpp
- :emphasize-lines: 7,8,31,32,34
+ :emphasize-lines: 5,6,29,30,32
:language: c++
:linenos:
:name: new-type-usage-basic-read
@@ -71,7 +71,10 @@ Class template :cpp:class:`new_type`
new_type
The class template :cpp:class:`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.
+ Similarly to the newtype keyword in Haskell, this class template creates a new type that is layout equivalent to the underlying type.
+ During creation of the of new strong type, features can be derived using :cpp:any:`nt::deriving`.
+ Actual feature availability depends on the :cpp:any:`BaseType` chosen for :cpp:class:`new_type` instance.
+ For example, deriving :cpp:any:`nt::Show` for a :cpp:class:`new_type` instance over a type not supporting output on a standard output stream, will not cause the instance to be output-streamable.
:tparam BaseType: |BaseTypeDoc|
:tparam TagType: |TagTypeDoc|
@@ -89,25 +92,25 @@ Class template :cpp:class:`new_type`
.. cpp:type:: iterator = typename BaseType::iterator
- :enablement: This type alias shall be defined iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` has a member type :cpp:type:`iterator <new_type::base_type::iterator>` and the :cpp:var:`derivation clause <derivation_clause>` contains :cpp:var:`Iterable`.
+ :enablement: This type alias is defined iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` has a member type :cpp:type:`iterator <new_type::base_type::iterator>` and the :cpp:var:`derivation clause <derivation_clause>` contains :cpp:var:`Iterable`.
.. versionadded:: 1.1.0
.. cpp:type:: const_iterator = typename BaseType::const_iterator
- :enablement: This type alias shall be defined iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` has a member type :cpp:type:`const_iterator <new_type::base_type::const_iterator>` and the :cpp:var:`derivation clause <derivation_clause>` contains :cpp:var:`Iterable`.
+ :enablement: This type alias is defined iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` has a member type :cpp:type:`const_iterator <new_type::base_type::const_iterator>` and the :cpp:var:`derivation clause <derivation_clause>` contains :cpp:var:`Iterable`.
.. versionadded:: 1.1.0
.. cpp:type:: reverse_iterator = typename BaseType::reverse_iterator
- :enablement: This type alias shall be defined iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` has a member type :cpp:type:`reverse_iterator <new_type::base_type::reverse_iterator>` and the :cpp:var:`derivation clause <derivation_clause>` contains :cpp:var:`Iterable`.
+ :enablement: This type alias is defined iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` has a member type :cpp:type:`reverse_iterator <new_type::base_type::reverse_iterator>` and the :cpp:var:`derivation clause <derivation_clause>` contains :cpp:var:`Iterable`.
.. versionadded:: 1.1.0
.. cpp:type:: const_reverse_iterator = typename BaseType::const_reverse_iterator
- :enablement: This type alias shall be defined iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` has a member type :cpp:type:`const_reverse_iterator <new_type::base_type::const_reverse_iterator>` and the :cpp:var:`derivation clause <derivation_clause>` contains :cpp:var:`Iterable`.
+ :enablement: This type alias is defined iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` has a member type :cpp:type:`const_reverse_iterator <new_type::base_type::const_reverse_iterator>` and the :cpp:var:`derivation clause <derivation_clause>` contains :cpp:var:`Iterable`.
.. versionadded:: 1.1.0
@@ -117,18 +120,18 @@ Class template :cpp:class:`new_type`
**Constructors**
- .. cpp:function:: constexpr new_type()
+ .. cpp:function:: constexpr new_type() noexcept(std::is_nothrow_default_constructible_v<base_type>)
Construct a new instance of this :cpp:class:`new_type` by default constructing the contained object.
:throws: Any exception thrown by the default constructor of this :cpp:class:`new_type`'s :cpp:type:`base_type`.
- This constructor shall be noexcept iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is *nothrow default-construtible*.
- :enablement: This constructor shall be defined as :literal:`= default` iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is *default-construtible*.
- Otherwise, this constructor shall be explicitely deleted.
+ This constructor is noexcept iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is *nothrow default-construtible*.
+ :enablement: This constructor is defined as :cpp:expr:`= default` iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is *default-construtible*.
+ Otherwise, this constructor is declared as explicitely deleted.
- .. cpp:function:: constexpr new_type(new_type const & other)
+ .. cpp:function:: constexpr new_type(new_type const & other) noexcept(std::is_nothrow_copy_constructible_v<base_type>)
- Construct a new instance of this :cpp:class:`new_type` by copy-constructing the contained object using the value contained by :literal:`other`.
+ Construct a new instance of this :cpp:class:`new_type` by copy-constructing the contained object using the value contained by :cpp:any:`other`.
:param other: An existing instance of this :cpp:class:`new_type`
:throws: Any exception thrown by the copy-constructor of this :cpp:class:`new_type`'s :cpp:type:`base_type`.
diff --git a/source/examples/CMakeLists.txt b/source/examples/CMakeLists.txt
index 45d1638..73d961e 100644
--- a/source/examples/CMakeLists.txt
+++ b/source/examples/CMakeLists.txt
@@ -1,11 +1,14 @@
-function(add_example NAME)
- add_executable("ex_${NAME}" "src/${NAME}.cpp")
- target_link_libraries("ex_${NAME}" "${PROJECT_NAME}")
-endfunction()
+file(GLOB SOURCES
+ RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
+ CONFIGURE_DEPENDS
+ "src/*.cpp"
+)
-add_example("basic_usage")
-add_example("basic_usage_with_show")
-add_example("basic_usage_with_read")
+foreach(EXAMPLE IN LISTS SOURCES)
+ get_filename_component(NAME "${EXAMPLE}" NAME_WE)
+ add_executable("ex_${NAME}" "${EXAMPLE}")
+ target_link_libraries("ex_${NAME}" "newtype::newtype")
+endforeach()
install(DIRECTORY "src/"
TYPE DOC
diff --git a/source/lib/include/newtype/newtype.hpp b/source/lib/include/newtype/newtype.hpp
index 3654afd..25c7313 100644
--- a/source/lib/include/newtype/newtype.hpp
+++ b/source/lib/include/newtype/newtype.hpp
@@ -2,6 +2,7 @@
#define NEWTYPE_NEWTYPE_HPP
#include <algorithm>
+#include <compare>
#include <functional>
#include <istream>
#include <ostream>
@@ -13,196 +14,70 @@ namespace nt
namespace impl
{
-
inline namespace storage
{
-
- template<typename BaseType, typename TagType>
+ template<typename T>
struct new_type_storage
{
- constexpr new_type_storage() noexcept(std::is_nothrow_default_constructible_v<BaseType>)
- : m_value{}
- {
- }
-
- constexpr new_type_storage(BaseType const & value)
- : m_value{value}
- {
- }
-
- constexpr new_type_storage(BaseType && value)
- : m_value{std::move(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;
+ T m_value;
};
-
- 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;
-
- constexpr 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;
- constexpr new_type_copy_constructor(BaseType const &) = delete;
- 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;
- constexpr new_type_move_constructor(BaseType &&) = 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 storage
inline namespace member_types
{
template<typename T, bool = false, typename = std::void_t<>>
- struct new_type_iterator
+ struct new_type_iterator : new_type_storage<T>
{
};
template<typename T>
- struct new_type_iterator<T, true, std::void_t<typename T::iterator>>
+ struct new_type_iterator<T, true, std::void_t<typename T::iterator>> : new_type_storage<T>
{
using iterator = typename T::iterator;
};
- template<typename T, bool = false, typename = std::void_t<>>
- struct new_type_const_iterator
+ template<typename T, bool Enabled = false, typename = std::void_t<>>
+ struct new_type_const_iterator : new_type_iterator<T, Enabled>
{
};
template<typename T>
- struct new_type_const_iterator<T, true, std::void_t<typename T::const_iterator>>
+ struct new_type_const_iterator<T, true, std::void_t<typename T::const_iterator>> : new_type_iterator<T, true>
{
using const_iterator = typename T::const_iterator;
};
- template<typename T, bool = false, typename = std::void_t<>>
- struct new_type_reverse_iterator
+ template<typename T, bool Enabled = false, typename = std::void_t<>>
+ struct new_type_reverse_iterator : new_type_const_iterator<T, Enabled>
{
};
template<typename T>
- struct new_type_reverse_iterator<T, true, std::void_t<typename T::reverse_iterator>>
+ struct new_type_reverse_iterator<T, true, std::void_t<typename T::reverse_iterator>> : new_type_const_iterator<T, true>
{
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, bool Enabled = false, typename = std::void_t<>>
+ struct new_type_const_reverse_iterator : new_type_reverse_iterator<T, Enabled>
{
};
template<typename T>
- struct new_type_const_reverse_iterator<T, true, std::void_t<typename T::const_reverse_iterator>>
+ struct new_type_const_reverse_iterator<T, true, std::void_t<typename T::const_reverse_iterator>> : new_type_reverse_iterator<T, true>
{
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>
+ struct new_type_iterator_types : new_type_const_reverse_iterator<T, Enabled>
{
};
} // namespace member_types
- } // namespace impl
+ } // namespace impl
inline namespace lib
{
@@ -294,6 +169,14 @@ namespace nt
{
template<typename SubjectType>
+ concept nothrow_three_way_comparable = requires(SubjectType lhs, SubjectType rhs) {
+ requires std::three_way_comparable<SubjectType>;
+ {
+ lhs <=> rhs
+ } noexcept;
+ };
+
+ template<typename SubjectType>
concept equality_comparable = requires(SubjectType lhs, SubjectType rhs) {
{
lhs == rhs
@@ -778,96 +661,14 @@ namespace nt
}
template<typename BaseType, typename TagType, auto DerivationClause = deriving()>
- class new_type
- : impl::new_type_move_assignment<BaseType, TagType>
- , public impl::new_type_iterator_types<BaseType, nt::derives<decltype(DerivationClause), nt::Iterable>>
+ class new_type : public impl::new_type_iterator_types<BaseType, nt::derives<decltype(DerivationClause), nt::Iterable>>
{
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");
static_assert(!derives<decltype(DerivationClause), nt::Relational, nt::ThreewayCompare>,
"Cannot derive both nt::Relational and nt::ThreewayCompare at the same time.");
- template<typename CharType,
- typename StreamTraits,
- nt::concepts::input_streamable<CharType, StreamTraits> BaseTypeT,
- typename TagTypeT,
- nt::derives<nt::Read> auto DerivationClauseV>
- auto friend operator>>(std::basic_istream<CharType, StreamTraits> &, new_type<BaseTypeT, TagTypeT, DerivationClauseV> &) noexcept(
- nt::concepts::nothrow_input_streamable<BaseTypeT, CharType, StreamTraits>) -> std::basic_istream<CharType, StreamTraits> &;
-
- template<nt::concepts::compound_addable BaseTypeT, typename TagTypeT, nt::derives<nt::Arithmetic> auto DerivationClauseV>
- auto constexpr friend
- operator+=(new_type<BaseTypeT, TagTypeT, DerivationClauseV> & lhs,
- new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & rhs) noexcept(nt::concepts::nothrow_compound_addable<BaseTypeT>)
- -> new_type<BaseTypeT, TagTypeT, DerivationClauseV> &;
-
- template<nt::concepts::compound_subtractable BaseTypeT, typename TagTypeT, nt::derives<nt::Arithmetic> auto DerivationClauseV>
- auto constexpr friend
- operator-=(new_type<BaseTypeT, TagTypeT, DerivationClauseV> & lhs,
- new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & rhs) noexcept(nt::concepts::nothrow_compound_subtractable<BaseTypeT>)
- -> new_type<BaseTypeT, TagTypeT, DerivationClauseV> &;
-
- template<nt::concepts::compound_multipliable BaseTypeT, typename TagTypeT, nt::derives<nt::Arithmetic> auto DerivationClauseV>
- auto constexpr friend
- operator*=(new_type<BaseTypeT, TagTypeT, DerivationClauseV> & lhs,
- new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & rhs) noexcept(nt::concepts::nothrow_compound_multipliable<BaseTypeT>)
- -> new_type<BaseTypeT, TagTypeT, DerivationClauseV> &;
-
- template<nt::concepts::compound_divisible BaseTypeT, typename TagTypeT, nt::derives<nt::Arithmetic> auto DerivationClauseV>
- auto constexpr friend
- operator/=(new_type<BaseTypeT, TagTypeT, DerivationClauseV> & lhs,
- new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & rhs) noexcept(nt::concepts::nothrow_compound_divisible<BaseTypeT>)
- -> new_type<BaseTypeT, TagTypeT, DerivationClauseV> &;
-
- template<nt::concepts::free_begin BaseTypeT, typename TagTypeT, nt::derives<nt::Iterable> auto DerivationClauseV>
- auto constexpr friend begin(new_type<BaseTypeT, TagTypeT, DerivationClauseV> & obj) ->
- typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::iterator;
-
- template<nt::concepts::const_free_begin BaseTypeT, typename TagTypeT, nt::derives<nt::Iterable> auto DerivationClauseV>
- auto constexpr friend begin(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj) ->
- typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_iterator;
-
- template<nt::concepts::free_cbegin BaseTypeT, typename TagTypeT, nt::derives<nt::Iterable> auto DerivationClauseV>
- auto constexpr friend cbegin(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj) ->
- typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_iterator;
-
- template<nt::concepts::free_rbegin BaseTypeT, typename TagTypeT, nt::derives<nt::Iterable> auto DerivationClauseV>
- auto constexpr friend rbegin(new_type<BaseTypeT, TagTypeT, DerivationClauseV> & obj) ->
- typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::reverse_iterator;
-
- template<nt::concepts::const_free_rbegin BaseTypeT, typename TagTypeT, nt::derives<nt::Iterable> auto DerivationClauseV>
- auto constexpr friend rbegin(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj) ->
- typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_reverse_iterator;
-
- template<nt::concepts::free_crbegin BaseTypeT, typename TagTypeT, nt::derives<nt::Iterable> auto DerivationClauseV>
- auto constexpr friend crbegin(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj) ->
- typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_reverse_iterator;
-
- template<nt::concepts::free_end BaseTypeT, typename TagTypeT, nt::derives<nt::Iterable> auto DerivationClauseV>
- auto constexpr friend end(new_type<BaseTypeT, TagTypeT, DerivationClauseV> & obj) ->
- typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::iterator;
-
- template<nt::concepts::const_free_end BaseTypeT, typename TagTypeT, nt::derives<nt::Iterable> auto DerivationClauseV>
- auto constexpr friend end(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj) ->
- typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_iterator;
-
- template<nt::concepts::free_cend BaseTypeT, typename TagTypeT, nt::derives<nt::Iterable> auto DerivationClauseV>
- auto constexpr friend cend(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj) ->
- typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_iterator;
-
- template<nt::concepts::free_rend BaseTypeT, typename TagTypeT, nt::derives<nt::Iterable> auto DerivationClauseV>
- auto constexpr friend rend(new_type<BaseTypeT, TagTypeT, DerivationClauseV> & obj) ->
- typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::reverse_iterator;
-
- template<nt::concepts::const_free_rend BaseTypeT, typename TagTypeT, nt::derives<nt::Iterable> auto DerivationClauseV>
- auto constexpr friend rend(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj) ->
- typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_reverse_iterator;
-
- template<nt::concepts::free_crend BaseTypeT, typename TagTypeT, nt::derives<nt::Iterable> auto DerivationClauseV>
- auto constexpr friend crend(new_type<BaseTypeT, TagTypeT, DerivationClauseV> const & obj) ->
- typename new_type<BaseTypeT, TagTypeT, DerivationClauseV>::const_reverse_iterator;
-
- using super = impl::new_type_move_assignment<BaseType, TagType>;
+ using super = impl::new_type_iterator_types<BaseType, nt::derives<decltype(DerivationClause), nt::Iterable>>;
public:
using base_type = BaseType;
@@ -876,11 +677,29 @@ namespace nt
auto constexpr static derivation_clause = DerivationClause;
- using super::super;
+ constexpr new_type() noexcept(std::is_nothrow_default_constructible_v<BaseType>)
+ requires std::constructible_from<BaseType>
+ = default;
+
+ constexpr new_type(new_type const &) noexcept(std::is_nothrow_copy_constructible_v<BaseType>)
+ requires std::copy_constructible<BaseType>
+ = default;
+
+ constexpr new_type(new_type &&) noexcept(std::is_nothrow_move_constructible_v<BaseType>)
+ requires std::move_constructible<BaseType>
+ = default;
+
+ constexpr new_type(BaseType const & base) noexcept(std::is_nothrow_copy_constructible_v<BaseType>)
+ requires std::copy_constructible<BaseType>
+ : super{base}
+ {
+ }
- constexpr new_type() noexcept(std::is_nothrow_default_constructible_v<BaseType>) = default;
- constexpr new_type(new_type const &) noexcept(std::is_nothrow_copy_constructible_v<BaseType>) = default;
- constexpr new_type(new_type &&) noexcept(std::is_nothrow_move_constructible_v<BaseType>) = default;
+ constexpr new_type(BaseType && base) noexcept(std::is_nothrow_move_constructible_v<BaseType>)
+ requires std::move_constructible<BaseType>
+ : super{std::move(base)}
+ {
+ }
auto constexpr operator=(new_type const &) noexcept(std::is_nothrow_copy_assignable_v<BaseType>) -> new_type & = default;
auto constexpr operator=(new_type &&) noexcept(std::is_nothrow_move_assignable_v<BaseType>) -> new_type & = default;
@@ -899,369 +718,365 @@ namespace nt
template<typename DerivationClauseT = decltype(DerivationClause)>
explicit constexpr operator base_type() const noexcept(std::is_nothrow_copy_constructible_v<base_type>)
- requires(!nt::derives<DerivationClauseT, nt::ImplicitConversion>)
+ requires(nt::doesnt_derive<DerivationClauseT, nt::ImplicitConversion>)
{
return decay();
}
- template<typename DerivationClauseT = decltype(DerivationClause)>
- requires(nt::derives<DerivationClauseT, nt::Indirection>)
- auto constexpr operator->() noexcept -> BaseType *
+ template<typename CharType, typename StreamTraits, nt::concepts::input_streamable<CharType, StreamTraits> BaseTypeT = BaseType>
+ auto friend operator>>(std::basic_istream<CharType, StreamTraits> & in,
+ new_type & obj) noexcept(nt::concepts::nothrow_input_streamable<BaseTypeT, CharType, StreamTraits>)
+ -> std::basic_istream<CharType, StreamTraits> &
+ requires nt::derives<decltype(DerivationClause), nt::Read>
{
- return std::addressof(this->m_value);
+ return in >> obj.m_value;
}
- template<typename DerivationClauseT = decltype(DerivationClause)>
- requires(nt::derives<DerivationClauseT, nt::Indirection>)
- auto constexpr operator->() const noexcept -> BaseType const *
+ template<typename CharType, typename StreamTraits, nt::concepts::output_streamable<CharType, StreamTraits> BaseTypeT = BaseType>
+ auto friend operator<<(std::basic_ostream<CharType, StreamTraits> & out,
+ new_type const & obj) noexcept(nt::concepts::nothrow_output_streamable<BaseType, CharType, StreamTraits>)
+ -> std::basic_ostream<CharType, StreamTraits> &
+ requires nt::derives<decltype(DerivationClause), nt::Show>
{
- return std::addressof(this->m_value);
+ return out << obj.m_value;
}
- template<nt::concepts::member_begin BaseTypeT = BaseType, nt::derives<nt::Iterable> auto DerivationClauseV = DerivationClause>
- auto constexpr begin() -> typename new_type<BaseTypeT, TagType, DerivationClauseV>::iterator
+ /**
+ * @brief Check two instances of nt::new_type<BaseType, TagType, DerivationClause> for equality.
+ *
+ * @param lhs The left-hand side of the comparison.
+ * @param rhs The right-hand side of the comparison.
+ *
+ * @note This overload is available iff. the underlying type is equality-comparable and this nt::new_type does not derive
+ * nt::ThreewayCompare.
+ *
+ * @return The value returned by the comparison of the underlying objects.
+ *
+ * @throws Any exception thrown by the comparison operator of the underlying objects of @ref lhs and @ref rhs. `noexcept` iff.
+ * new_type::base_type is nothrow equality-comparable.
+ */
+
+ // THREE-WAY ORDER AND EQUAL
+
+ auto constexpr operator<=>(new_type const & rhs) const noexcept(nt::concepts::nothrow_three_way_comparable<BaseType>)
+ requires(std::three_way_comparable<BaseType> && nt::derives<derivation_clause_type, nt::ThreewayCompare>)
{
- return this->m_value.begin();
+ return decay() <=> rhs.decay();
}
- template<nt::concepts::const_member_begin BaseTypeT = BaseType, nt::derives<nt::Iterable> auto DerivationClauseV = DerivationClause>
- auto constexpr begin() const -> typename new_type<BaseTypeT, TagType, DerivationClauseV>::const_iterator
+ auto constexpr operator==(new_type const & rhs) const -> bool
+ requires(nt::concepts::equality_comparable<BaseType> && nt::derives<derivation_clause_type, nt::ThreewayCompare>)
{
- return this->m_value.begin();
+ return decay() == rhs.decay();
}
- template<nt::concepts::member_cbegin BaseTypeT = BaseType, nt::derives<nt::Iterable> auto DerivationClauseV = DerivationClause>
- auto constexpr cbegin() const -> typename new_type<BaseTypeT, TagType, DerivationClauseV>::const_iterator
- {
- return this->m_value.cbegin();
- }
+ // NOT THREE-WAY EQUAL
- template<nt::concepts::member_cbegin BaseTypeT = BaseType, nt::derives<nt::Iterable> auto DerivationClauseV = DerivationClause>
- auto constexpr rbegin() -> typename new_type<BaseTypeT, TagType, DerivationClauseV>::reverse_iterator
+ auto constexpr operator==(new_type const & rhs) const noexcept(nt::concepts::nothrow_equality_comparable<BaseType>) -> bool
+ requires(nt::concepts::equality_comparable<BaseType> && nt::doesnt_derive<derivation_clause_type, nt::ThreewayCompare>)
{
- return this->m_value.rbegin();
+ return decay() == rhs.decay();
}
- template<nt::concepts::member_cbegin BaseTypeT = BaseType, nt::derives<nt::Iterable> auto DerivationClauseV = DerivationClause>
- auto constexpr rbegin() const -> typename new_type<BaseTypeT, TagType, DerivationClauseV>::const_reverse_iterator
+ // BASE EQUAL
+
+ auto constexpr operator==(BaseType const & rhs) const noexcept(nt::concepts::nothrow_equality_comparable<BaseType>) -> bool
+ requires(nt::concepts::equality_comparable<BaseType> && nt::derives<derivation_clause_type, nt::EqBase>)
{
- return this->m_value.rbegin();
+ return decay() == rhs;
}
- template<nt::concepts::member_crbegin BaseTypeT = BaseType, nt::derives<nt::Iterable> auto DerivationClauseV = DerivationClause>
- auto constexpr crbegin() const -> typename new_type<BaseTypeT, TagType, DerivationClauseV>::const_reverse_iterator
+ // NOT THREE-WAY EQUAL
+
+ auto constexpr operator!=(new_type const & rhs) const noexcept(nt::concepts::nothrow_inequality_comparable<BaseType>) -> bool
+ requires(nt::concepts::inequality_comparable<BaseType> && nt::doesnt_derive<derivation_clause_type, nt::ThreewayCompare>)
{
- return this->m_value.crbegin();
+ return decay() != rhs.decay();
}
- template<nt::concepts::member_end BaseTypeT = BaseType, nt::derives<nt::Iterable> auto DerivationClauseV = DerivationClause>
- auto constexpr end() -> typename new_type<BaseTypeT, TagType, DerivationClauseV>::iterator
+ // NOT THREE-WAY ORDER
+
+ auto constexpr operator<(new_type const & rhs) const noexcept(nt::concepts::nothrow_less_than_comparable<BaseType>) -> bool
+ requires(nt::concepts::less_than_comparable<BaseType> && //
+ nt::doesnt_derive<derivation_clause_type, nt::ThreewayCompare> && //
+ nt::derives<derivation_clause_type, nt::Relational>)
{
- return this->m_value.end();
+ return decay() < rhs.decay();
}
- template<nt::concepts::const_member_end BaseTypeT = BaseType, nt::derives<nt::Iterable> auto DerivationClauseV = DerivationClause>
- auto constexpr end() const -> typename new_type<BaseTypeT, TagType, DerivationClauseV>::const_iterator
+ auto constexpr operator<=(new_type const & rhs) const noexcept(nt::concepts::nothrow_less_than_equal_comparable<BaseType>) -> bool
+ requires(nt::concepts: