diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2023-12-21 16:14:04 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2023-12-21 16:14:04 +0100 |
| commit | d3987d09b3e89316fc39e1681de0432eebec35df (patch) | |
| tree | c7e2fb4482c8c567c415a8ea6c400db807a409d9 | |
| parent | 0f2c94a59de9837a1eee7b849d309088c4be8154 (diff) | |
| download | newtype-d3987d09b3e89316fc39e1681de0432eebec35df.tar.xz newtype-d3987d09b3e89316fc39e1681de0432eebec35df.zip | |
new_type: simplify implementation
| -rw-r--r-- | .vscode/c_cpp_properties.json | 3 | ||||
| -rw-r--r-- | .vscode/settings.json | 5 | ||||
| -rw-r--r-- | conanfile.py | 4 | ||||
| -rw-r--r-- | source/doc/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | source/doc/src/index.rst | 39 | ||||
| -rw-r--r-- | source/examples/CMakeLists.txt | 17 | ||||
| -rw-r--r-- | source/lib/include/newtype/newtype.hpp | 845 | ||||
| -rw-r--r-- | source/tests/src/threeway_comparison.cpp | 2 |
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(); } |
