aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt28
-rw-r--r--doc/src/index.rst301
-rw-r--r--examples/src/basic_usage.cpp39
-rw-r--r--examples/src/basic_usage_with_read.cpp39
-rw-r--r--examples/src/basic_usage_with_show.cpp41
-rw-r--r--include/newtype/impl/new_type_storage.hpp1
-rw-r--r--include/newtype/new_type.hpp18
7 files changed, 323 insertions, 144 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 55d4da0..1067eb6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -94,6 +94,13 @@ if(BUILD_DOCS)
message(FATAL_ERROR "Could not find pipenv")
endif()
+ set(DOC_SOURCES
+ "${PROJECT_SOURCE_DIR}/doc/src/index.rst"
+ "${PROJECT_SOURCE_DIR}/doc/src/conf.py"
+ "${PROJECT_SOURCE_DIR}/examples/src/basic_usage.cpp"
+ "${PROJECT_SOURCE_DIR}/examples/src/basic_usage_with_show.cpp"
+ )
+
add_custom_target("pipenv_install"
COMMAND "${PIPENV_EXE}" "install" ">/dev/null"
COMMENT "Installing pipenv dependencies"
@@ -110,14 +117,14 @@ if(BUILD_DOCS)
add_custom_command(OUTPUT "${PROJECT_BINARY_DIR}/doc/html/index.html"
COMMAND "${PIPENV_EXE}" "run" "sphinx-build" "-b" "singlehtml" "${PROJECT_SOURCE_DIR}/doc/src" "${PROJECT_BINARY_DIR}/doc/html" ">/dev/null"
- DEPENDS "${PROJECT_SOURCE_DIR}/doc/src/index.rst" "${PROJECT_SOURCE_DIR}/doc/src/conf.py"
+ DEPENDS ${DOC_SOURCES}
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/doc"
COMMENT "Compiling HTML documentation"
)
add_custom_command(OUTPUT "${PROJECT_BINARY_DIR}/doc/man/newtype.3"
COMMAND "${PIPENV_EXE}" "run" "sphinx-build" "-b" "man" "${PROJECT_SOURCE_DIR}/doc/src" "${PROJECT_BINARY_DIR}/doc/man" ">/dev/null"
- DEPENDS "${PROJECT_SOURCE_DIR}/doc/src/index.rst" "${PROJECT_SOURCE_DIR}/doc/src/conf.py"
+ DEPENDS ${DOC_SOURCES}
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/doc"
COMMENT "Compiling man pages"
)
@@ -135,7 +142,22 @@ if(BUILD_DOCS)
install(FILES "${PROJECT_BINARY_DIR}/doc/man/${PROJECT_NAME}.3"
DESTINATION "share/man/man3"
)
- endif()
+endif()
+
+# 'newtype' examples
+
+option(BUILD_EXAMPLES "Build the library examples" OFF)
+
+if(BUILD_EXAMPLES)
+ add_executable("ex_basic_usage" "examples/src/basic_usage.cpp")
+ target_link_libraries("ex_basic_usage" "${PROJECT_NAME}")
+
+ add_executable("ex_basic_usage_with_show" "examples/src/basic_usage_with_show.cpp")
+ target_link_libraries("ex_basic_usage_with_show" "${PROJECT_NAME}")
+
+ add_executable("ex_basic_usage_with_read" "examples/src/basic_usage_with_read.cpp")
+ target_link_libraries("ex_basic_usage_with_read" "${PROJECT_NAME}")
+endif()
# CMake support files
diff --git a/doc/src/index.rst b/doc/src/index.rst
index ab52381..ac24f36 100644
--- a/doc/src/index.rst
+++ b/doc/src/index.rst
@@ -1,204 +1,223 @@
+.. cpp:namespace-push:: nt
+
#############
Documentation
#############
The ``newtype`` library provides types and functions to facilitate the creation of strong type aliases.
-API
-===
+Example Usage
+#############
-.. cpp:namespace-push:: nt
+: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`.
+
+.. literalinclude:: ../../examples/src/basic_usage.cpp
+ :language: c++
+ :linenos:
+ :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.
+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.
+
+.. literalinclude:: ../../examples/src/basic_usage_with_show.cpp
+ :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`.
+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
+ :language: c++
+ :linenos:
+ :name: new-type-usage-basic-read
+ :caption: Deriving input operations using the :cpp:var:`Read` derivation tag
+
+API
+###
This section of the documentation describes the public API of the *new_type*.
It provides detailed descriptions of the types and functions designed to be used by applications.
Additionally, this section provides usage examples that demonstrate the use and properties of the public API.
+Header :literal:`<newtype/new_type.hpp>`
+========================================
+
+This header contains the definitions of the class template :cpp:class:`new_type` as well as a set of associated namespace-level functions.
+
Class template :cpp:class:`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.
+
.. cpp:class:: template<typename BaseType, typename TagType, auto DerivationClause = deriving()> \
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 :literal:`newtype`, this class template creates a new type that is layout equivalent to the underlying type.
+ **Member Type Aliases**
- :tparam BaseType: The underlying type of the new strong alias
- :tparam TagType: A type uniquely identifying this string alias
- :tparam DerivationClause: A :cpp:class:`derivation_clause` listing all features that shall be automatically derived.
+ .. cpp:type:: base_type = BaseType
+ .. cpp:type:: tag_type = TagType
-Usage
-~~~~~
+ .. cpp:type:: derivation_clause_type = decltype(DerivationClause)
-:ref:`new-type-usage-simple` below demonstrate the most basic usage of :cpp:class:`new_type`.
-In it, :cpp:class:`new_type` is used to create a new strong alias :literal:`width` for :literal:`unsigned int`.
+ **Static Data Members**
-.. code-block:: c++
- :linenos:
- :name: new-type-usage-simple
- :caption: Creating a new strong alias for :literal:`unsigned int`
+ .. cpp:var:: derivation_clause_type constexpr static derivation_clause = DerivationClause
- #include <newtype/new_type.hpp>
+ **Constructors**
- using width = nt::new_type<unsigned int, struct width_tag>;
+ .. cpp:function:: constexpr new_type()
-The class template :cpp:class:`new_type` expects the desired underlying type as its first template argument, :literal:`unsigned int` in the example above.
-As a second template argument, :cpp:class:`new_type` expects a tag- or phantom-type.
-Neither the underlying type, nor the tag-type are is required to be complete.
+ **noexcept specification:** This constructor shall be noexcept iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is nothrow default-construtible.
-The class template :cpp:class:`new_type` takes as a third template argument an instance of :cpp:class:`derivation_clause`.
-Derivation clauses make it possible to let the implementation derive certain operations automatically.
-For example, the derivation tag :cpp:var:`Arithmetic` enables automatic derivation of arithmetic operations for a given instance of :cpp:class:`new_type` (see :ref:`new-type-usage-deriving-arithmetic` below).
+ **default definition:** 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.
-.. code-block:: c++
- :linenos:
- :name: new-type-usage-deriving-arithmetic
- :caption: Automatically deriving arithmetic operations
+ .. cpp:function:: constexpr new_type(new_type const &)
- #include <newtype/new_type.hpp>
+ **noexcept specification:**: This constructor shall be noexcept iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is nothrow copy-construtible.
- using width = nt::new_type<unsigned int, struct width_tag, deriving(nt::Arithmetic)>;
+ **default definition:** This constructor shall be defined as :literal:`= default` iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is copy-construtible.
+ Otherwise, this constructor shall be explicitely deleted.
-Synopsis
-~~~~~~~~
+ .. cpp:function:: constexpr new_type(new_type &&)
-.. code-block:: c++
+ **noexcept specification:**: This constructor shall be noexcept iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is nothrow move-construtible.
- namespace nt
- {
- template<typename BaseType, typename TagType, auto DerivationClause = deriving()>
- class new_type
- {
- public:
+ **default definition:** This constructor shall be defined as :literal:`= default` iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is move-construtible.
+ Otherwise, this constructor shall be explicitely deleted.
- // Type aliases
+ .. cpp:function:: constexpr new_type(BaseType &)
- using base_type = BaseType;
- using tag_type = TagType;
- using derivation_clause_type = decltype(DerivationClause);
+ **noexcept specification:** This constructor shall be noexcept iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is nothrow copy-construtible.
- // Derivation clause access
+ **enablement:** This constructor shall be defined iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is copy-construtible.
+ Otherwise, this constructor shall be explicitely deleted.
- auto constexpr static derivation_clause = DerivationClause;
+ .. cpp:function:: constexpr new_type(BaseType &&)
- // Constructors
+ **noexcept specification:** This constructor shall be noexcept iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is nothrow move-construtible.
- constexpr new_type() noexcept(std::is_nothrow_default_constructible_v<BaseType>) = /*see below*/;
+ **enablement:** This constructor shall be defined iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is move-construtible.
+ Otherwise, this constructor shall be explicitely deleted.
- constexpr new_type(new_type const &) noexcept(std::is_nothrow_copy_constructible_v<BaseType>) = /*see below*/;
+ **Assignment Operators**
- constexpr new_type(new_type &&) noexcept(std::is_nothrow_move_constructible_v<BaseType>) = /*see below*/;
+ .. cpp:function:: constexpr new_type & operator=(new_type const &)
- constexpr explicit new_type(BaseType const &) noexcept(std::is_nothrow_copy_constructible_v<BaseType>);
+ **noexcept specification:** This assignment operator shall be noexcept iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is nothrow copy-assignable.
- constexpr explicit new_type(BaseType &&) noexcept(std::is_nothrow_move_constructible_v<BaseType>);
+ **default definition:** This assignment operator shall be defined as :literal:`= default` iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is copy-assignable.
+ Otherwise, this assignment operator shall be explicitely deleted.
- // Assignment operators
+ .. cpp:function:: constexpr new_type & operator=(new_type &&)
- auto constexpr operator=(new_type const &) noexcept(std::is_nothrow_copy_assignable_v<BaseType>) -> new_type & = /*see below*/
+ **noexcept specification:** This assignment operator shall be noexcept iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is nothrow move-assignable.
- auto constexpr operator=(new_type &&) noexcept(std::is_nothrow_move_assignable_v<BaseType>) -> new_type & = /*see below*/
+ **default definition:** This assignment operator shall be defined as :literal:`= default` iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is move-assignable.
+ Otherwise, this assignment operator shall be explicitely deleted.
- // Accessors
+ **Accessors**
- auto constexpr decay() const noexcept -> BaseType;
+ .. cpp:function:: constexpr BaseType decay() const
- /* EXPLICIT: see below */ constexpr operator base_type() const noexcept(/*see below*/)
+ **noexcept specification:** This member function shall be noexcept iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is nothrow copy-assignable.
- // Indirection operators
+ .. cpp:function:: constexpr operator BaseType() const
- auto constexpr operator->() noexcept -> std::enable_if_t<DerivationClause(nt::Indirection), BaseType *>;
+ **noexcept specification:** This conversion operator shall be noexcept iff. this :cpp:class:`new_type`'s :cpp:type:`base_type` is nothrow copy-assignable.
- auto constexpr operator->() const noexcept -> std::enable_if_t<DerivationClause(nt::Indirection), BaseType const *>;
+ **explicit specification:** This conversion operator shall be explicit unless this :cpp:class:`new_type`'s :cpp:var:`derivation_clause` contains :cpp:var:`ImplicitConversion`.
- private:
- BaseType m_value; // exposition only
- };
+ **Member Access Trough Pointer**
- // Equality comparison operators
-
- template<typename BaseType,
- typename TagType,
- auto DerivationClause>
- auto constexpr operator==(new_type<BaseType, TagType, DerivationClause> const &,
- new_type<BaseType, TagType, DerivationClause> const &) noexcept(/*see below*/)
- -> bool;
-
- template<typename BaseType,
- typename TagType,
- auto DerivationClause>
- auto constexpr operator!=(new_type<BaseType, TagType, DerivationClause> const &,
- new_type<BaseType, TagType, DerivationClause> const &) noexcept(/*see below*/)
- -> bool;
-
- // Relational operators
-
- template<typename BaseType,
- typename TagType,
- auto DerivationClause>
- auto constexpr operator<(new_type<BaseType, TagType, DerivationClause> const &,
- new_type<BaseType, TagType, DerivationClause> const &) noexcept(/*see below*/)
- -> std::enable_if_t<DerivationClause(nt::Relational) && /*see below*/, bool>;
-
- template<typename BaseType,
- typename TagType,
- auto DerivationClause>
- auto constexpr operator>(new_type<BaseType, TagType, DerivationClause> const &,
- new_type<BaseType, TagType, DerivationClause> const &) noexcept(/*see below*/)
- -> std::enable_if_t<DerivationClause(nt::Relational) && /*see below*/, bool>;
-
- template<typename BaseType,
- typename TagType,
- auto DerivationClause>
- auto constexpr operator<=(new_type<BaseType, TagType, DerivationClause> const &,
- new_type<BaseType, TagType, DerivationClause> const &) noexcept(/*see below*/)
- -> std::enable_if_t<DerivationClause(nt::Relational) && /*see below*/, bool>;
-
- template<typename BaseType,
- typename TagType,
- auto DerivationClause>
- auto constexpr operator>=(new_type<BaseType, TagType, DerivationClause> const &,
- new_type<BaseType, TagType, DerivationClause> const &) noexcept(/*see below*/)
- -> std::enable_if_t<DerivationClause(nt::Relational) && /*see below*/, bool>;
-
- // Stream input/output operators
-
- template<typename BaseType,
- typename TagType,
- auto DerivationClause,
- typename CharType,
- typename StreamTraits>
- auto operator<<(std::basic_ostream<CharType, StreamTraits> &,
- new_type<BaseType, TagType, DerivationClause> const &) noexcept(/*see below*/)
- -> std::enable_if_t<DerivationClause(nt::Show) && /*see below*/, std::basic_ostream<CharType, StreamTraits>> &;
-
- template<typename BaseType,
- typename TagType,
- auto DerivationClause,
- typename CharType,
- typename StreamTraits>
- auto operator>>(std::basic_istream<CharType, StreamTraits> &,
- new_type<BaseType, TagType, DerivationClause> &) noexcept(/*see below*/)
- -> std::enable_if_t<DerivationClause(nt::Read) && /*see below*/, std::basic_istream<CharType, StreamTraits>> &;
- }
+ .. cpp:function:: constexpr BaseType operator->() noexcept
+
+ **enablement:** This operator shall be available iff. this :cpp:class:`new_type`'s :cpp:var:`derivation_clause` contains :cpp:var:`Indirection`
+
+ .. cpp:function:: constexpr BaseType const * operator->() const noexcept
+
+ **enablement:** This operator shall be available iff. this :cpp:class:`new_type`'s :cpp:var:`derivation_clause` contains :cpp:var:`Indirection`
+
+Namespace-level functions and function templates
+------------------------------------------------
+
+The functions and functions templates described in this section provide additional functionality for the class template :cpp:class:`new_type` that is not part of the class itself.
+
+Equality Comparison Operators
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. cpp:function:: template<typename BaseType, \
+ typename TagType, \
+ auto DerivationClause> \
+ constexpr bool operator==(new_type<BaseType, TagType, DerivationClause> const &,\
+ new_type<BaseType, TagType, DerivationClause> const &)
+
+ **noexcept specification:** This conversion operator shall be noexcept iff. :cpp:type:`new_type<BaseType, TagType, DerivationClause>::base_type` is nothrow equals-comparable.
+
+ **enablement:** This operator shall be available iff. :cpp:type:`new_type<BaseType, TagType, DerivationClause>::base_type` supports comparison using the operator :literal:`==`
+
+.. cpp:function:: template<typename BaseType, \
+ typename TagType, \
+ auto DerivationClause> \
+ constexpr bool operator!=(new_type<BaseType, TagType, DerivationClause> const &,\
+ new_type<BaseType, TagType, DerivationClause> const &)
+
+ **noexcept specification:** This conversion operator shall be noexcept iff. :cpp:type:`new_type<BaseType, TagType, DerivationClause>::base_type` is nothrow not-equals-comparable.
+
+ **enablement:** This operator shall be available iff. this :cpp:type:`new_type<BaseType, TagType, DerivationClause>::base_type` supports comparison using the operator :literal:`!=`
+
+Relational Comparison Operators
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. cpp:function:: template<typename BaseType, \
+ typename TagType, \
+ auto DerivationClause> \
+ constexpr bool operator<(new_type<BaseType, TagType, DerivationClause> const &, \
+ new_type<BaseType, TagType, DerivationClause> const &)
-Member Type Aliases
-~~~~~~~~~~~~~~~~~~~
+.. cpp:function:: template<typename BaseType, \
+ typename TagType, \
+ auto DerivationClause> \
+ constexpr bool operator>(new_type<BaseType, TagType, DerivationClause> const &, \
+ new_type<BaseType, TagType, DerivationClause> const &)
-Static Data Members
-~~~~~~~~~~~~~~~~~~~
+.. cpp:function:: template<typename BaseType, \
+ typename TagType, \
+ auto DerivationClause> \
+ constexpr bool operator<=(new_type<BaseType, TagType, DerivationClause> const &, \
+ new_type<BaseType, TagType, DerivationClause> const &)
-Special Member Functions
-~~~~~~~~~~~~~~~~~~~~~~~~
+.. cpp:function:: template<typename BaseType, \
+ typename TagType, \
+ auto DerivationClause> \
+ constexpr bool operator>=(new_type<BaseType, TagType, DerivationClause> const &, \
+ new_type<BaseType, TagType, DerivationClause> const &)
-Free Equality Comparison Operators
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Stream I/O Operators
+~~~~~~~~~~~~~~~~~~~~
-Free Relational Operators
-~~~~~~~~~~~~~~~~~~~~~~~~~
+.. cpp:function:: template<typename BaseType, \
+ typename TagType, \
+ auto DerivationClause, \
+ typename CharType, \
+ typename StreamTraits> \
+ std::basic_ostream<CharType, StreamTraits> & operator<<(std::basic_ostream<CharType, StreamTraits> &, \
+ new_type<BaseType, TagType, DerivationClause> const &)
-Free Stream Input/Ouput Operators
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. cpp:function:: template<typename BaseType, \
+ typename TagType, \
+ auto DerivationClause, \
+ typename CharType, \
+ typename StreamTraits> \
+ std::basic_istream<CharType, StreamTraits> & operator>>(std::basic_istream<CharType, StreamTraits> &, \
+ new_type<BaseType, TagType, DerivationClause> &)
Class template :cpp:class:`derivation_clause`
---------------------------------------------
diff --git a/examples/src/basic_usage.cpp b/examples/src/basic_usage.cpp
new file mode 100644
index 0000000..a2a50cd
--- /dev/null
+++ b/examples/src/basic_usage.cpp
@@ -0,0 +1,39 @@
+#include <newtype/new_type.hpp>
+
+#include <iostream>
+
+using Width = nt::new_type<unsigned int, struct width_tag>;
+using Height = nt::new_type<unsigned int, struct height_tag>;
+using Area = nt::new_type<unsigned int, struct area_tag>;
+
+struct Rectangle
+{
+ constexpr Rectangle(Width w, Height h)
+ : width{w}
+ , height{h}
+ {
+ }
+
+ auto constexpr area() const noexcept -> Area
+ {
+ return {width.decay() * height.decay()};
+ }
+
+private:
+ Width width;
+ Height height;
+};
+
+int main()
+{
+ auto w{0u}, h{0u};
+
+ std::cin >> w >> h;
+
+ auto width = Width{w};
+ auto height = Height{h};
+
+ auto rect = Rectangle{width, height};
+
+ std::cout << rect.area().decay() << '\n';
+} \ No newline at end of file
diff --git a/examples/src/basic_usage_with_read.cpp b/examples/src/basic_usage_with_read.cpp
new file mode 100644
index 0000000..87fcc1a
--- /dev/null
+++ b/examples/src/basic_usage_with_read.cpp
@@ -0,0 +1,39 @@
+#include <newtype/derivable.hpp>
+#include <newtype/deriving.hpp>
+#include <newtype/new_type.hpp>
+
+#include <iostream>
+
+using Width = nt::new_type<unsigned int, struct width_tag, deriving(nt::Read)>;
+using Height = nt::new_type<unsigned int, struct height_tag, deriving(nt::Read)>;
+using Area = nt::new_type<unsigned int, struct area_tag, deriving(nt::Show)>;
+
+struct Rectangle
+{
+ constexpr Rectangle(Width w, Height h)
+ : width{w}
+ , height{h}
+ {
+ }
+
+ auto constexpr area() const noexcept -> Area
+ {
+ return {width.decay() * height.decay()};
+ }
+
+private:
+ Width width;
+ Height height;
+};
+
+int main()
+{
+ auto width = Width{};
+ auto height = Height{};
+
+ std::cin >> width >> height;
+
+ auto rect = Rectangle{width, height};
+
+ std::cout << rect.area() << '\n';
+} \ No newline at end of file
diff --git a/examples/src/basic_usage_with_show.cpp b/examples/src/basic_usage_with_show.cpp
new file mode 100644
index 0000000..1a83968
--- /dev/null
+++ b/examples/src/basic_usage_with_show.cpp
@@ -0,0 +1,41 @@
+#include <newtype/derivable.hpp>
+#include <newtype/deriving.hpp>
+#include <newtype/new_type.hpp>
+
+#include <iostream>
+
+using Width = nt::new_type<unsigned int, struct width_tag>;
+using Height = nt::new_type<unsigned int, struct height_tag>;
+using Area = nt::new_type<unsigned int, struct area_tag, deriving(nt::Show)>;
+
+struct Rectangle
+{
+ constexpr Rectangle(Width w, Height h)
+ : width{w}
+ , height{h}
+ {
+ }
+
+ auto constexpr area() const noexcept -> Area
+ {
+ return {width.decay() * height.decay()};
+ }
+
+private:
+ Width width;
+ Height height;
+};
+
+int main()
+{
+ auto w{0u}, h{0u};
+
+ std::cin >> w >> h;
+
+ auto width = Width{w};
+ auto height = Height{h};
+
+ auto rect = Rectangle{width, height};
+
+ std::cout << rect.area() << '\n';
+} \ No newline at end of file
diff --git a/include/newtype/impl/new_type_storage.hpp b/include/newtype/impl/new_type_storage.hpp
index 5f64771..5cec601 100644
--- a/include/newtype/impl/new_type_storage.hpp
+++ b/include/newtype/impl/new_type_storage.hpp
@@ -2,6 +2,7 @@
#define NEWTYPE_IMPL_NEW_TYPE_STORAGE_HPP
#include <type_traits>
+#include <utility>
namespace nt::impl
{
diff --git a/include/newtype/new_type.hpp b/include/newtype/new_type.hpp
index 0b7d6d0..77b531e 100644
--- a/include/newtype/new_type.hpp
+++ b/include/newtype/new_type.hpp
@@ -39,6 +39,8 @@ namespace nt
using super = impl::new_type_move_assignment<BaseType, TagType>;
public:
+ /// @section Type aliases
+
/**
* @brief The base type of this nt::new_type
*
@@ -60,6 +62,8 @@ namespace nt
*/
using derivation_clause_type = decltype(DerivationClause);
+ /// @section Derivation clause access
+
/**
* @brief The derivation clause fo this nt::new_type
*
@@ -67,6 +71,8 @@ namespace nt
*/
auto constexpr static derivation_clause = DerivationClause;
+ /// @section Constructors
+
using super::super;
/**
@@ -95,6 +101,8 @@ namespace nt
*/
constexpr new_type(new_type &&) noexcept(std::is_nothrow_move_constructible_v<BaseType>) = default;
+ /// @section Assignment operators
+
/**
* @brief Copy-assign the value of an existing instance of this nt::new_type to this instance
*
@@ -115,6 +123,8 @@ namespace nt
*/
auto constexpr operator=(new_type &&) noexcept(std::is_nothrow_move_assignable_v<BaseType>) -> new_type & = default;
+ /// @section Accessors
+
/**
* @brief Obtain a copy of the contained base type object
*
@@ -147,6 +157,8 @@ namespace nt
return decay();
}
+ /// @section Indirection operators
+
/**
* @brief Perform an access to a member of the base type
*
@@ -170,6 +182,8 @@ namespace nt
}
};
+ /// @section Equality comparison operators
+
/**
* @brief Compare two objects for equality
*
@@ -202,6 +216,8 @@ namespace nt
return lhs.decay() != rhs.decay();
}
+ /// @section Relational operators
+
/**
* @brief Check if one nt::new_type object is less-than an other
*
@@ -274,6 +290,8 @@ namespace nt
return lhs.decay() >= rhs.decay();
}
+ /// @section Stream input/output operators
+
/**
* @brief Write the contained base type object to a standard output stream
*