From dcef4c05289ea9007a5f041899d4955c8c03fa9b Mon Sep 17 00:00:00 2001 From: Braxton Salyer Date: Mon, 29 Jan 2024 22:59:27 -0600 Subject: [PATCH] Start documenting current items --- CMakeLists.txt | 57 +- docs/Doxyfile | 5 +- docs/concepts.rst | 9 + docs/concepts/comparable.rst | 12 + docs/conf.py | 1 - docs/index.rst | 9 + docs/type_traits.rst | 14 + docs/type_traits/is_comparable.rst | 4 + docs/type_traits/is_operator_able.rst | 4 + include/hyperion/mpl.h | 39 + include/hyperion/mpl/concepts.h | 13 + include/hyperion/mpl/concepts/comparable.h | 81 +- include/hyperion/mpl/concepts/operator_able.h | 57 +- include/hyperion/mpl/type_traits.h | 12 + .../hyperion/mpl/type_traits/is_comparable.h | 174 ++- .../mpl/type_traits/is_operator_able.h | 1088 ++++++++++++++++- xmake.lua | 4 + 17 files changed, 1457 insertions(+), 126 deletions(-) create mode 100644 docs/concepts.rst create mode 100644 docs/concepts/comparable.rst create mode 100644 docs/type_traits.rst create mode 100644 docs/type_traits/is_comparable.rst create mode 100644 docs/type_traits/is_operator_able.rst create mode 100644 include/hyperion/mpl.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 40f0e75..c0afd91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,26 +41,27 @@ endif() include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/hyperion_compiler_settings.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/hyperion_enable_warnings.cmake) -set(HYPERION_PLATFORM_INCLUDE_DIRECTORIES +set(HYPERION_MPL_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/include" ) -set(HYPERION_PLATFORM_INCLUDE_PATH +set(HYPERION_MPL_INCLUDE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/include/hyperion" ) -set(HYPERION_PLATFORM_HEADERS - "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/index.h" - "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/list.h" - "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/value.h" - "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/algorithms.h" - "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/algorithms/all_of.h" - "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/concepts.h" - "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/concepts/comparable.h" - "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/concepts/operator_able.h" - "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/concepts/std_supplemental.h" - "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/type_traits.h" - "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/type_traits/is_comparable.h" - "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/type_traits/is_operator_able.h" - "${HYPERION_PLATFORM_INCLUDE_PATH}/mpl/type_traits/std_supplemental.h" +set(HYPERION_MPL_HEADERS + "${HYPERION_MPL_INCLUDE_PATH}/mpl.h" + "${HYPERION_MPL_INCLUDE_PATH}/mpl/index.h" + "${HYPERION_MPL_INCLUDE_PATH}/mpl/list.h" + "${HYPERION_MPL_INCLUDE_PATH}/mpl/value.h" + "${HYPERION_MPL_INCLUDE_PATH}/mpl/algorithms.h" + "${HYPERION_MPL_INCLUDE_PATH}/mpl/algorithms/all_of.h" + "${HYPERION_MPL_INCLUDE_PATH}/mpl/concepts.h" + "${HYPERION_MPL_INCLUDE_PATH}/mpl/concepts/comparable.h" + "${HYPERION_MPL_INCLUDE_PATH}/mpl/concepts/operator_able.h" + "${HYPERION_MPL_INCLUDE_PATH}/mpl/concepts/std_supplemental.h" + "${HYPERION_MPL_INCLUDE_PATH}/mpl/type_traits.h" + "${HYPERION_MPL_INCLUDE_PATH}/mpl/type_traits/is_comparable.h" + "${HYPERION_MPL_INCLUDE_PATH}/mpl/type_traits/is_operator_able.h" + "${HYPERION_MPL_INCLUDE_PATH}/mpl/type_traits/std_supplemental.h" ) add_library(hyperion_mpl INTERFACE) @@ -68,12 +69,12 @@ add_library(hyperion::mpl ALIAS hyperion_mpl) target_include_directories( hyperion_mpl INTERFACE - ${HYPERION_PLATFORM_INCLUDE_DIRECTORIES} + ${HYPERION_MPL_INCLUDE_DIRECTORIES} ) target_sources( hyperion_mpl INTERFACE - ${HYPERION_PLATFORM_HEADERS} + ${HYPERION_MPL_HEADERS} ) target_link_libraries( hyperion_mpl @@ -95,20 +96,20 @@ target_link_libraries(hyperion_mpl_main hyperion_compile_settings(hyperion_mpl_main) hyperion_enable_warnings(hyperion_mpl_main) -set(HYPERION_PLATFORM_DOXYGEN_OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/docs/_build/html") -set(HYPERION_PLATFORM_DOXYGEN_HTML "${HYPERION_PLATFORM_DOXYGEN_OUTPUT_DIR}/index.html") +set(HYPERION_MPL_DOXYGEN_OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/docs/_build/html") +set(HYPERION_MPL_DOXYGEN_HTML "${HYPERION_MPL_DOXYGEN_OUTPUT_DIR}/index.html") -set(HYPERION_PLATFORM_DOCS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/docs") -set(HYPERION_PLATFORM_DOCS_FILES - "${HYPERION_PLATFORM_DOCS_DIR}/index.rst" - "${HYPERION_PLATFORM_DOCS_DIR}/quick_start.rst" +set(HYPERION_MPL_DOCS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/docs") +set(HYPERION_MPL_DOCS_FILES + "${HYPERION_MPL_DOCS_DIR}/index.rst" + "${HYPERION_MPL_DOCS_DIR}/quick_start.rst" ) add_custom_command( - OUTPUT ${HYPERION_PLATFORM_DOXYGEN_HTML} - DEPENDS ${HYPERION_PLATFORM_HEADERS} ${DOCS_FILES} + OUTPUT ${HYPERION_MPL_DOXYGEN_HTML} + DEPENDS ${HYPERION_MPL_HEADERS} ${DOCS_FILES} COMMAND sphix-build -M html . _build - WORKING_DIRECTORY ${HYPERION_PLATFORM_DOCS_DIR} + WORKING_DIRECTORY ${HYPERION_MPL_DOCS_DIR} MAIN_DEPENDENCY COMMENT "Generating documentation with doxygen, sphinx, and breathe" VERBATIM @@ -117,6 +118,6 @@ add_custom_command( add_custom_target(hyperion_mpl_doxygen DEPENDS ${DOXYGEN_HTML}) include(GNUInstallDirs) -install(DIRECTORY ${HYPERION_PLATFORM_DOXYGEN_OUTPUT_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR}) +install(DIRECTORY ${HYPERION_MPL_DOXYGEN_OUTPUT_DIR} DESTINATION ${CMAKE_INSTALL_DOCDIR}) install(DIRECTORY include/ DESTINATION include) install(TARGETS hyperion_mpl DESTINATION lib) diff --git a/docs/Doxyfile b/docs/Doxyfile index 1db56a3..b5af854 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -44,7 +44,7 @@ PROJECT_NUMBER = # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = "Platform and Architecture Detection and Feature Test Macros for C++. Part of Hyperion Engine." +PROJECT_BRIEF = "C++20 Metaprogramming library inspired by Boost.Hana. Part of Hyperion Engine." # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 @@ -2205,8 +2205,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = IGNORE_PADDING_START=""\ - IGNORE_PADDING_STOP="" +PREDEFINED = HYPERION_PLATFORM_STD_LIB_HAS_COMPARE=1 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/docs/concepts.rst b/docs/concepts.rst new file mode 100644 index 0000000..ae48902 --- /dev/null +++ b/docs/concepts.rst @@ -0,0 +1,9 @@ +hyperion::mpl::concepts +************************** + +.. doxygengroup:: concepts + +.. toctree:: + :caption: Comparison Operator Detection + + concepts/comparable diff --git a/docs/concepts/comparable.rst b/docs/concepts/comparable.rst new file mode 100644 index 0000000..4b75514 --- /dev/null +++ b/docs/concepts/comparable.rst @@ -0,0 +1,12 @@ +Comparability Concepts +********************** + +.. doxygengroup:: comparability_concepts + +.. doxygenconcept:: hyperion::mpl::concepts::EqualityComparable +.. doxygenconcept:: hyperion::mpl::concepts::InequalityComparable +.. doxygenconcept:: hyperion::mpl::concepts::LessThanComparable +.. doxygenconcept:: hyperion::mpl::concepts::LessThanOrEqualComparable +.. doxygenconcept:: hyperion::mpl::concepts::GreaterThanComparable +.. doxygenconcept:: hyperion::mpl::concepts::GreaterThanOrEqualComparable +.. doxygenconcept:: hyperion::mpl::concepts::ThreeWayComparable diff --git a/docs/conf.py b/docs/conf.py index a3e9077..2010c9c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -114,5 +114,4 @@ "hyperion::mpl": "_build/xml" } breathe_default_project = "hyperion::mpl" -breathe_default_members = ('members') diff --git a/docs/index.rst b/docs/index.rst index 2c84793..4056a02 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -26,3 +26,12 @@ For an overview of each module, see the links in the left sidebar or below. genindex +.. toctree:: + :caption: Type Traits + + type_traits + +.. toctree:: + :caption: Concept Definitions + + concepts diff --git a/docs/type_traits.rst b/docs/type_traits.rst new file mode 100644 index 0000000..77815c9 --- /dev/null +++ b/docs/type_traits.rst @@ -0,0 +1,14 @@ +hyperion::mpl::type_traits +************************** + +.. doxygengroup:: type_traits + +.. toctree:: + :caption: Comparison Operator Detection + + type_traits/is_comparable + +.. toctree:: + :caption: General Operator Detection + + type_traits/is_operator_able diff --git a/docs/type_traits/is_comparable.rst b/docs/type_traits/is_comparable.rst new file mode 100644 index 0000000..7b40166 --- /dev/null +++ b/docs/type_traits/is_comparable.rst @@ -0,0 +1,4 @@ +Comparison Operator Detection +***************************** + +.. doxygengroup:: comparison_operator_detection diff --git a/docs/type_traits/is_operator_able.rst b/docs/type_traits/is_operator_able.rst new file mode 100644 index 0000000..6ffdbc7 --- /dev/null +++ b/docs/type_traits/is_operator_able.rst @@ -0,0 +1,4 @@ +General Operator Detection +***************************** + +.. doxygengroup:: general_operator_detection diff --git a/include/hyperion/mpl.h b/include/hyperion/mpl.h new file mode 100644 index 0000000..722b2cc --- /dev/null +++ b/include/hyperion/mpl.h @@ -0,0 +1,39 @@ +/// @file mpl.h +/// @author Braxton Salyer +/// @brief Catch-all header for the Hyperion meta-programming library +/// @version 0.1 +/// @date 2024-01-27 +/// +/// MIT License +/// @copyright Copyright (c) 2024 Braxton Salyer +/// +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in all +/// copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +#ifndef HYPERION_MPL_H +#define HYPERION_MPL_H + +/// @defgroup mpl Metaprogramming Library +/// Hyperion's metaprogramming library provides a full-featured set of basic +/// metaprogramming operations, inspired by Boost.Hana. It uses `constexpr` and value +/// semantics to make metaprogramming functional, simple, and (mostly) read and write +/// like normal code for users, instead of needing to rely on complex template-based +/// techniques that are difficult to reason about. +/// @headerfile "hyperion/mpl.h" + +#endif // HYPERION_MPL_H diff --git a/include/hyperion/mpl/concepts.h b/include/hyperion/mpl/concepts.h index 93b9aa8..6502100 100644 --- a/include/hyperion/mpl/concepts.h +++ b/include/hyperion/mpl/concepts.h @@ -28,6 +28,19 @@ #ifndef HYPERION_MPL_CONCEPTS_H #define HYPERION_MPL_CONCEPTS_H +/// @ingroup mpl +/// @{ +/// @defgroup concepts Concepts +/// Hyperion provides an assortment of metaprogramming `concept` definitions used to +/// define various conceptual models and characteristics of types. +/// Some of these are purely novel, such as comparability, while others are supplemental +/// to, or less stringent than, those provided by the standard, doing something similar +/// to existing `concept`s, but filling in gaps in the API surface that were overlooked +/// or missing for other reasons, or provided an alternative definition that is narrower +/// in scope. +/// @headerfile hyperion/mpl/concepts.h +/// @} + #include #include #include diff --git a/include/hyperion/mpl/concepts/comparable.h b/include/hyperion/mpl/concepts/comparable.h index 31f18ac..030ec82 100644 --- a/include/hyperion/mpl/concepts/comparable.h +++ b/include/hyperion/mpl/concepts/comparable.h @@ -29,33 +29,91 @@ #ifndef HYPERION_MPL_CONCEPTS_COMPARABLE_H #define HYPERION_MPL_CONCEPTS_COMPARABLE_H -#include +#include + +#if HYPERION_PLATFORM_STD_LIB_HAS_COMPARE + #include +#endif // HYPERION_PLATFORM_STD_LIB_HAS_COMPARE + +/// @ingroup concepts +/// @{ +/// @defgroup comparability_concepts Comparability Concepts +/// Assortment of `concept` definitions requiring types to +/// be comparable in various ways. +/// +/// # Example: +/// @code {.cpp} +/// #include ); +/// static_assert(!EqualityComparable); +/// +/// @endcode +/// @headerfile hyperion/mpl/concepts/comparable.h +/// @} namespace hyperion::mpl::concepts { + /// @brief Concept definition requiring that a `TLhs` is + /// equality comparable with a `TRhs` + /// @ingroup comparability_concepts + /// @headerfile hyperion/mpl/concepts/comparable.h template - concept EqualityComparable = type_traits::is_equality_comparable_v; - + concept EqualityComparable = requires(const TLhs& lhs, const TRhs& rhs) { + lhs == rhs; + rhs == lhs; + }; + + /// @brief Concept definition requiring that a `TLhs` is + /// inequality comparable with a `TRhs` + /// @ingroup comparability_concepts + /// @headerfile hyperion/mpl/concepts/comparable.h template - concept InequalityComparable = type_traits::is_inequality_comparable_v; - + concept InequalityComparable = requires(const TLhs& lhs, const TRhs& rhs) { + lhs != rhs; + rhs != lhs; + }; + + /// @brief Concept definition requiring that a `TLhs` is + /// less-than comparable with a `TRhs` + /// @ingroup comparability_concepts + /// @headerfile hyperion/mpl/concepts/comparable.h template - concept LessThanComparable = type_traits::is_less_than_comparable_v; + concept LessThanComparable = requires(const TLhs& lhs, const TRhs& rhs) { lhs < rhs; }; + /// @brief Concept definition requiring that a `TLhs` is + /// less-than-or-equal comparable with a `TRhs` + /// @ingroup comparability_concepts + /// @headerfile hyperion/mpl/concepts/comparable.h template - concept LessThanOrEqualComparable = type_traits::is_less_than_or_equal_comparable_v; + concept LessThanOrEqualComparable = requires(const TLhs& lhs, const TRhs& rhs) { lhs <= rhs; }; + /// @brief Concept definition requiring that a `TLhs` is + /// greater-than comparable with a `TRhs` + /// @ingroup comparability_concepts + /// @headerfile hyperion/mpl/concepts/comparable.h template - concept GreaterThanComparable = type_traits::is_greater_than_comparable_v; + concept GreaterThanComparable = requires(const TLhs& lhs, const TRhs& rhs) { lhs > rhs; }; + /// @brief Concept definition requiring that a `TLhs` is + /// greater-than-or-equal comparable with a `TRhs` + /// @ingroup comparability_concepts + /// @headerfile hyperion/mpl/concepts/comparable.h template concept GreaterThanOrEqualComparable - = type_traits::is_greater_than_or_equal_comparable_v; + = requires(const TLhs& lhs, const TRhs& rhs) { lhs >= rhs; }; #if HYPERION_PLATFORM_STD_LIB_HAS_COMPARE + /// @brief Concept definition requiring that a `TLhs` is + /// three-way comparable with a `TRhs` + /// @ingroup comparability_concepts + /// @headerfile hyperion/mpl/concepts/comparable.h template - concept ThreeWayComparable = type_traits::is_three_way_comparable_v; + concept ThreeWayComparable = std::three_way_comparable_with; #endif // HYPERION_PLATFORM_STD_LIB_HAS_COMPARE @@ -115,7 +173,8 @@ namespace hyperion::mpl::concepts { "hyperion::mpl::concepts::ThreeWayComparable test case 3 failing"); #endif // HYPERION_PLATFORM_STD_LIB_HAS_COMPARE - } // namespace _test + + } // namespace _test } // namespace hyperion::mpl::concepts #endif // HYPERION_MPL_CONCEPTS_IS_COMPARABLE_H diff --git a/include/hyperion/mpl/concepts/operator_able.h b/include/hyperion/mpl/concepts/operator_able.h index 78889f0..14a96b9 100644 --- a/include/hyperion/mpl/concepts/operator_able.h +++ b/include/hyperion/mpl/concepts/operator_able.h @@ -29,51 +29,78 @@ #ifndef HYPERION_MPL_CONCEPTS_OPERATOR_ABLE_H #define HYPERION_MPL_CONCEPTS_OPERATOR_ABLE_H -#include +#include namespace hyperion::mpl::concepts { template - concept UnaryPlusable = type_traits::is_unary_plusable_v; + concept UnaryPlusable = requires(const TLhs& lhs) { +lhs; }; template - concept UnaryMinusable = type_traits::is_unary_minusable_v; + concept UnaryMinusable = requires(const TLhs& lhs) { -lhs; }; template - concept BinaryNotable = type_traits::is_binary_notable_v; + concept BinaryNotable = requires(const TLhs& lhs) { ~lhs; }; template - concept BooleanNotable = type_traits::is_boolean_notable_v; + concept BooleanNotable = requires(const TLhs& lhs) { !lhs; }; template - concept Addressable = type_traits::is_addressable_v; + concept Addressable = requires(const TLhs& lhs) { &lhs; }; template - concept Arrowable = type_traits::is_arrowable_v; + concept Dereferencible = std::is_pointer_v || requires(const TLhs& lhs) { *lhs; }; + + template + concept Arrowable = std::is_pointer_v || requires(const TLhs& lhs) { lhs.operator->(); }; template - concept Addable = type_traits::is_addable_v; + concept Addable = requires(const TLhs& lhs, const TRhs& rhs) { + lhs + rhs; + rhs + lhs; + }; template - concept Subtractable = type_traits::is_subtractable_v; + concept Subtractable = requires(const TLhs& lhs, const TRhs& rhs) { + lhs - rhs; + rhs - lhs; + }; template - concept Multipliable = type_traits::is_multipliable_v; + concept Multipliable = requires(const TLhs& lhs, const TRhs& rhs) { + lhs* rhs; + rhs* lhs; + }; template - concept Dividible = type_traits::is_dividible_v; + concept Dividible = requires(const TLhs& lhs, const TRhs& rhs) { + lhs / rhs; + rhs / lhs; + }; template - concept BinaryAndable = type_traits::is_binary_andable_v; + concept BinaryAndable = requires(const TLhs& lhs, const TRhs& rhs) { + lhs & rhs; + rhs & lhs; + }; template - concept BinaryOrable = type_traits::is_binary_orable_v; + concept BinaryOrable = requires(const TLhs& lhs, const TRhs& rhs) { + lhs | rhs; + rhs | lhs; + }; template - concept BooleanAndable = type_traits::is_boolean_andable_v; + concept BooleanAndable = requires(const TLhs& lhs, const TRhs& rhs) { + lhs&& rhs; + rhs&& lhs; + }; template - concept BooleanOrable = type_traits::is_boolean_orable_v; + concept BooleanOrable = requires(const TLhs& lhs, const TRhs& rhs) { + lhs || rhs; + rhs || lhs; + }; } // namespace hyperion::mpl::concepts diff --git a/include/hyperion/mpl/type_traits.h b/include/hyperion/mpl/type_traits.h index b6851e8..91f0594 100644 --- a/include/hyperion/mpl/type_traits.h +++ b/include/hyperion/mpl/type_traits.h @@ -28,6 +28,18 @@ #ifndef HYPERION_MPL_TYPE_TRAITS_H #define HYPERION_MPL_TYPE_TRAITS_H +/// @ingroup mpl +/// @{ +/// @defgroup type_traits Type Traits +/// Hyperion provides an assortment of metaprogramming type traits used to detect +/// various characteristics of given type(s). Some of these are purely novel, +/// such as detection of an operator overload, while others are supplemental to +/// those provided by the standard, doing something similar to existing traits, +/// but filling in gaps in the API surface that were overlooked or missing for +/// other reasons. +/// @headerfile hyperion/mpl/type_traits.h +/// @} + #include #include #include diff --git a/include/hyperion/mpl/type_traits/is_comparable.h b/include/hyperion/mpl/type_traits/is_comparable.h index 18a46ed..10f0f57 100644 --- a/include/hyperion/mpl/type_traits/is_comparable.h +++ b/include/hyperion/mpl/type_traits/is_comparable.h @@ -29,6 +29,7 @@ #ifndef HYPERION_MPL_TYPE_TRAITS_IS_COMPARABLE_H #define HYPERION_MPL_TYPE_TRAITS_IS_COMPARABLE_H +#include #include #if HYPERION_PLATFORM_STD_LIB_HAS_COMPARE @@ -37,95 +38,178 @@ #include +/// @ingroup type_traits +/// @{ +/// @defgroup comparison_operator_detection Comparison Operator Detection +/// Assortment of type traits to determine if two types are comparable. +/// +/// # Example: +/// @code {.cpp} +/// #include +/// +/// using namespace hyperion::mpl::type_traits; +/// struct not_comparable {}; +/// +/// static_assert(is_equality_comparable_v); +/// static_assert(!is_equality_comparable_v); +/// +/// @endcode +/// @headerfile hyperion/mpl/type_traits/is_comparable.h +/// @} + namespace hyperion::mpl::type_traits { + namespace detail { + + } + // clang-format off + /// @brief Type trait to determine whether a value of type `TLhs` + /// is equality comparable with a value of type `TRhs`. + /// @tparam TLhs The left-hand side argument of the comparison + /// @tparam TRhs The right-hand side argument of the comparison + /// @ingroup comparison_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_comparable.h template struct is_equality_comparable - : std::bool_constant + : std::bool_constant> {}; // clang-format on + /// @brief Value of the type trait `is_equality_comparable`. + /// Used to determine whether a value of type `TLhs` is equality + /// comparable with a value of type `TRhs`. + /// @tparam TLhs The left-hand side argument of the comparison + /// @tparam TRhs The right-hand side argument of the comparison + /// @ingroup comparison_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_comparable.h template static inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; // clang-format off + /// @brief Type trait to determine whether a value of type `TLhs` + /// is inequality comparable with a value of type `TRhs`. + /// @tparam TLhs The left-hand side argument of the comparison + /// @tparam TRhs The right-hand side argument of the comparison + /// @ingroup comparison_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_comparable.h template struct is_inequality_comparable - : std::bool_constant + : std::bool_constant> {}; // clang-format on + /// @brief Value of the type trait `is_inequality_comparable`. + /// Used to determine whether a value of type `TLhs` is inequality + /// comparable with a value of type `TRhs`. + /// @tparam TLhs The left-hand side argument of the comparison + /// @tparam TRhs The right-hand side argument of the comparison + /// @ingroup comparison_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_comparable.h template static inline constexpr auto is_inequality_comparable_v = is_inequality_comparable::value; // clang-format off + /// @brief Type trait to determine whether a value of type `TLhs` is + /// less-than comparable to a value of type `TRhs`. + /// @tparam TLhs The left-hand side argument of the comparison + /// @tparam TRhs The right-hand side argument of the comparison + /// @ingroup comparison_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_comparable.h template struct is_less_than_comparable - : std::bool_constant + : std::bool_constant> {}; // clang-format on + /// @brief Value of the type trait `is_less_than_comparable`. + /// Used to determine whether a value of type `TLhs` is less-than + /// comparable with a value of type `TRhs`. + /// @tparam TLhs The left-hand side argument of the comparison + /// @tparam TRhs The right-hand side argument of the comparison + /// @ingroup comparison_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_comparable.h template static inline constexpr auto is_less_than_comparable_v = is_less_than_comparable::value; // clang-format off + /// @brief Type trait to determine whether a value of type `TLhs` is + /// less-than-or-equal comparable to a value of type `TRhs`. + /// @tparam TLhs The left-hand side argument of the comparison + /// @tparam TRhs The right-hand side argument of the comparison + /// @ingroup comparison_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_comparable.h template struct is_less_than_or_equal_comparable - : std::bool_constant + : std::bool_constant> {}; // clang-format on + /// @brief Value of the type trait `is_less_than_or_equal_comparable`. + /// Used to determine whether a value of type `TLhs` is less-than-or-equal + /// comparable with a value of type `TRhs`. + /// @tparam TLhs The left-hand side argument of the comparison + /// @tparam TRhs The right-hand side argument of the comparison + /// @ingroup comparison_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_comparable.h template static inline constexpr auto is_less_than_or_equal_comparable_v = is_less_than_or_equal_comparable::value; // clang-format off + /// @brief Type trait to determine whether a value of type `TLhs` is + /// greater-than comparable to a value of type `TRhs`. + /// @tparam TLhs The left-hand side argument of the comparison + /// @tparam TRhs The right-hand side argument of the comparison + /// @ingroup comparison_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_comparable.h template struct is_greater_than_comparable - : std::bool_constant rhs); - (rhs > lhs); - }> + : std::bool_constant> {}; // clang-format on + /// @brief Value of the type trait `is_greater_than_comparable`. + /// Used to determine whether a value of type `TLhs` is greater-than + /// comparable with a value of type `TRhs`. + /// @tparam TLhs The left-hand side argument of the comparison + /// @tparam TRhs The right-hand side argument of the comparison + /// @ingroup comparison_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_comparable.h template static inline constexpr auto is_greater_than_comparable_v = is_greater_than_comparable::value; // clang-format off + /// @brief Type trait to determine whether a value of type `TLhs` is + /// greater-than-or-equal comparable to a value of type `TRhs`. + /// @tparam TLhs The left-hand side argument of the comparison + /// @tparam TRhs The right-hand side argument of the comparison + /// @ingroup comparison_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_comparable.h template struct is_greater_than_or_equal_comparable - : std::bool_constant= rhs; - rhs >= lhs; - }> + : std::bool_constant> {}; // clang-format on + /// @brief Value of the type trait `is_greater_than_or_equal_comparable`. + /// Used to determine whether a value of type `TLhs` is greater-than-or-equal + /// comparable with a value of type `TRhs`. + /// @tparam TLhs The left-hand side argument of the comparison + /// @tparam TRhs The right-hand side argument of the comparison + /// @ingroup comparison_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_comparable.h template static inline constexpr auto is_greater_than_or_equal_comparable_v = is_greater_than_or_equal_comparable::value; @@ -133,22 +217,60 @@ namespace hyperion::mpl::type_traits { #if HYPERION_PLATFORM_STD_LIB_HAS_COMPARE + /// @brief Type trait to determine whether a value of type `TLhs` is + /// three-way comparable to a value of type `TRhs`. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` is three-way comparable with a `TRhs`, also provides + /// the member `typedef` type `result_type` equal to the type of the returned + /// result of three-way comparing a `TLhs` with a `TRhs`, + /// i.e. `decltype(std::declval() <=> std::declval())` + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_three_way_comparable::value == false`, + /// then `result_type` will be `void` + /// + /// @tparam TLhs The left-hand side argument of the comparison + /// @tparam TRhs The right-hand side argument of the comparison + /// @ingroup comparison_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_comparable.h template struct is_three_way_comparable : std::false_type { using result_type = void; }; + // specialization for the true case + template - requires std::three_way_comparable_with + requires concepts::ThreeWayComparable struct is_three_way_comparable : std::true_type { using result_type = std::compare_three_way_result_t; }; // clang-format on + /// @brief Value of the type trait `is_three_way_comparable`. + /// Used to determine whether a value of type `TLhs` is + /// three-way comparable to a value of type `TRhs`. + /// + /// @tparam TLhs The left-hand side argument of the comparison + /// @tparam TRhs The right-hand side argument of the comparison + /// @ingroup comparison_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_comparable.h template static inline constexpr auto is_three_way_comparable_v = is_three_way_comparable::value; + /// @brief Alias to the `result_type` member typedef of `is_three_way_comparable`. + /// Used to determine the type of the returned result of three-way comparing + /// a `TLhs` with a `TRhs`, + /// i.e. `decltype(std::declval() <=> std::declval())` + /// + /// @tparam TLhs The left-hand side argument of the comparison + /// @tparam TRhs The right-hand side argument of the comparison + /// @ingroup comparison_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_comparable.h template using three_way_compare_result_t = typename is_three_way_comparable::result_type; @@ -164,6 +286,8 @@ namespace hyperion::mpl::type_traits { "hyperion::mpl::type_traits::is_equality_comparable test case 2 failing"); static_assert(!is_equality_comparable_v, "hyperion::mpl::type_traits::is_equality_comparable test case 3 failing"); + static_assert(!is_equality_comparable_v, + "hyperion::mpl::type_traits::is_equality_comparable test case 4 failing"); static_assert(is_inequality_comparable_v, "hyperion::mpl::type_traits::is_inequality_comparable test case 1 failing"); diff --git a/include/hyperion/mpl/type_traits/is_operator_able.h b/include/hyperion/mpl/type_traits/is_operator_able.h index 6822c63..0d71821 100644 --- a/include/hyperion/mpl/type_traits/is_operator_able.h +++ b/include/hyperion/mpl/type_traits/is_operator_able.h @@ -29,271 +29,1273 @@ #ifndef HYPERION_MPL_TYPE_TRAITS_IS_OPERATOR_ABLE_H #define HYPERION_MPL_TYPE_TRAITS_IS_OPERATOR_ABLE_H +#include #include +/// @ingroup type_traits +/// @{ +/// @defgroup general_operator_detection General Operator Detection +/// Assortment of type traits to determine if an overload of an operator +/// exists accepting one (or more) types. +/// +/// # Example: +/// @code {.cpp} +/// #include +/// +/// using namespace hyperion::mpl::type_traits; +/// struct not_addable {}; +/// +/// static_assert(is_addable_v); +/// static_assert(!is_addable_v); +/// +/// @endcode +/// @headerfile hyperion/mpl/type_traits/is_operator_able.h +/// @} + namespace hyperion::mpl::type_traits { + /// @brief Type Trait to determine if a type supports unary + /// `operator+`. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` supports unary `operator+`, also provides + /// the member `typedef` type `result_type` equal to the type of the + /// returned result of invoking the associated `operator+` overload, + /// i.e. `decltype(+std::declval())` + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_unary_plusable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator+` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_unary_plusable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template struct is_unary_plusable : std::false_type { using result_type = void; }; - template - requires requires(const TLhs& lhs) { +lhs; } + template struct is_unary_plusable : std::true_type { using result_type = decltype(+std::declval()); }; + /// @brief Value of the type trait `is_unary_plusable`. + /// Used to determine if a type supports unary `operator+`. + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator+` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_unary_plusable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template static inline constexpr auto is_unary_plusable_v = is_unary_plusable::value; + /// @brief Alias to the `result_type` member `typedef` of `is_unary_plusable`. + /// Used to determine the type of the returned result of invoking unary + /// `operator+` on a `TLhs`, i.e. `decltype(+std::declval())` + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_unary_plusable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator+` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_unary_plusable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template using unary_plus_result_t = typename is_unary_plusable::result_type; + /// @brief Type Trait to determine if a type supports unary + /// `operator-`. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` supports unary `operator-`, also provides + /// the member `typedef` type `result_type` equal to the type of the + /// returned result of invoking the associated `operator-` overload, + /// i.e. `decltype(-std::declval())` + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_unary_minusable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator-` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_unary_minusable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template struct is_unary_minusable : std::false_type { using result_type = void; }; - template - requires requires(const TLhs& lhs) { -lhs; } + template struct is_unary_minusable : std::true_type { using result_type = decltype(-std::declval()); }; + /// @brief Value of the type trait `is_unary_minusable`. + /// Used to determine if a type supports unary `operator-`. + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator-` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_unary_minusable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template static inline constexpr auto is_unary_minusable_v = is_unary_minusable::value; + /// @brief Alias to the `result_type` member `typedef` of `is_unary_minusable`. + /// Used to determine the type of the returned result of invoking unary + /// `operator-` on a `TLhs`, i.e. `decltype(-std::declval())` + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_unary_minusable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator-` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_unary_minusable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template using unary_minus_result_t = typename is_unary_minusable::result_type; + /// @brief Type Trait to determine if a type supports the binary + /// not operator, i.e. `operator~`. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` supports `operator~`, also provides + /// the member `typedef` type `result_type` equal to the type of the + /// returned result of invoking the associated `operator~` overload, + /// i.e. `decltype(~std::declval())` + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_binary_notable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator~` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_binary_notable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template struct is_binary_notable : std::false_type { using result_type = void; }; - template - requires requires(const TLhs& lhs) { ~lhs; } + template struct is_binary_notable : std::true_type { using result_type = decltype(~std::declval()); }; + /// @brief Value of the type trait `is_binary_notable`. + /// Used to determine if a type supports the binary not operator, + /// i.e. `operator~`. + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator~` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_binary_notable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template static inline constexpr auto is_binary_notable_v = is_binary_notable::value; + /// @brief Alias to the `result_type` member `typedef` of `is_binary_notable`. + /// Used to determine the type of the returned result of invoking + /// `operator~` on a `TLhs`, i.e. `decltype(~std::declval())` + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_binary_notable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator~` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_binary_notable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template using binary_not_result_t = typename is_binary_notable::result_type; + /// @brief Type Trait to determine if a type supports the boolean + /// not operator, i.e. `operator!`. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` supports `operator!`, also provides + /// the member `typedef` type `result_type` equal to the type of the + /// returned result of invoking the associated `operator!` overload, + /// i.e. `decltype(!std::declval())` + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_boolean_notable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator!` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_boolean_notable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template struct is_boolean_notable : std::false_type { using result_type = void; }; - template - requires requires(const TLhs& lhs) { !lhs; } + template struct is_boolean_notable : std::true_type { using result_type = decltype(!std::declval()); }; + /// @brief Value of the type trait `is_boolean_notable`. + /// Used to determine if a type supports the boolean not operator, + /// i.e. `operator!`. + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator!` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_boolean_notable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template static inline constexpr auto is_boolean_notable_v = is_boolean_notable::value; + /// @brief Alias to the `result_type` member `typedef` of `is_boolean_notable`. + /// Used to determine the type of the returned result of invoking + /// `operator!` on a `TLhs`, i.e. `decltype(!std::declval())` + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_boolean_notable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator!` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_boolean_notable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template using boolean_not_result_t = typename is_boolean_notable::result_type; + /// @brief Type Trait to determine if a type supports the address of + /// operator, i.e. unary `operator&`. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` supports unary `operator&`, also provides + /// the member `typedef` type `result_type` equal to the type of the + /// returned result of invoking the associated `operator&` overload, + /// i.e. `decltype(&std::declval())` + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_addressable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator&` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_addressable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template struct is_addressable : std::false_type { using result_type = void; }; - template + template requires requires(const TLhs& lhs) { &lhs; } struct is_addressable : std::true_type { using result_type = decltype(&std::declval()); }; + /// @brief Value of the type trait `is_addressable`. + /// Used to determine if a type supports the address of operator, + /// i.e. unary `operator&`. + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator&` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_addressable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template static inline constexpr auto is_addressable_v = is_addressable::value; + /// @brief Alias to the `result_type` member `typedef` of `is_addressable`. + /// Used to determine the type of the returned result of invoking + /// unary `operator&` on a `TLhs`, i.e. `decltype(&std::declval())` + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_addressable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator&` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_addressable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template using address_result_t = typename is_addressable::result_type; + /// @brief Type Trait to determine if a type supports the pointer to + /// member operator, i.e. `operator->`. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` supports `operator->`, also provides + /// the member `typedef` type `result_type` equal to the type of the + /// returned result of invoking the associated `operator->` overload, + /// i.e. `decltype(std::declval()->)` + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_arrowable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// `operator->` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_arrowable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template struct is_arrowable : std::false_type { using result_type = void; }; - template - requires std::is_pointer_v || requires(const TLhs& lhs) { lhs.operator->(); } + template struct is_arrowable : std::true_type { using result_type = std::conditional_t, std::remove_pointer_t, decltype(std::declval().operator->())>; }; + /// @brief Value of the type trait `is_arrowable`. + /// Used to determine if a type supports the pointer to member operator, + /// i.e. `operator->`. + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// `operator->` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_arrowable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template static inline constexpr auto is_arrowable_v = is_arrowable::value; + /// @brief Alias to the `result_type` member `typedef` of `is_arrowable`. + /// Used to determine the type of the returned result of invoking + /// `operator->` on a `TLhs`, i.e. `decltype(std::declval()->)` + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_arrowable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// `operator->` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_arrowable` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. template using arrow_result_t = typename is_arrowable::result_type; + /// @brief Type Trait to determine if a type supports the dereference + /// operator, i.e. unary `operator*`. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` supports unary `operator*`, also provides + /// the member `typedef` type `result_type` equal to the type of the + /// returned result of invoking the associated `operator*` overload, + /// i.e. `decltype(*std::declval())` + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_dereferencible::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator*` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_dereferencible` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. + template + struct is_dereferencible : std::false_type { + using result_type = void; + }; + + template + struct is_dereferencible : std::true_type { + using result_type = std::conditional_t, + std::remove_pointer_t, + decltype(std::declval().operator->())>; + }; + + /// @brief Value of the type trait `is_dereferencible`. + /// Used to determine if a type supports the dereference operator, + /// i.e. unary `operator*`. + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator*` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_dereferencible` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. + template + static inline constexpr auto is_dereferencible_v = is_dereferencible::value; + + /// @brief Alias to the `result_type` member `typedef` of `is_dereferencible`. + /// Used to determine the type of the returned result of invoking + /// unary `operator*` on a `TLhs`, i.e. `decltype(*std::declval())` + /// + /// @tparam TLhs The type to check + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_dereferencible::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification of the unqualified type + /// of `TLhs`. I.E., given a type `TType`, if you intend to invoke the + /// unary `operator*` overload associated with `TType` with a `const TType&`, + /// make sure that you instantiate and use `is_dereferencible` with + /// `TLhs = const TType&`, not `TType`, `TType&` or any other qualification. + template + using dereference_result_t = typename is_dereferencible::result_type; + + /// @brief Type trait to determine if `TLhs` and `TRhs` are addable. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` and `TRhs` are addable, also provides the member + /// `typedef` type `result_type` equal to the type of the returned result + /// of invoking the associated `operator+` overload, i.e. + /// `decltype(std::declval() + std::declval())`. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_addable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the addition operator (i.e. `operator+`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_addable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template struct is_addable : std::false_type { using result_type = void; }; template - requires requires(const TLhs& lhs, const TRhs& rhs) { - lhs + rhs; - rhs + lhs; - } + requires concepts::Addable struct is_addable : std::true_type { using result_type = decltype(std::declval() + std::declval()); }; + /// @brief Value of the type trait `is_addable` . + /// Used to determine if `TLhs` and `TRhs` are addable. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the addition operator (i.e. `operator+`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_addable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template static inline constexpr auto is_addable_v = is_addable::value; + /// @brief Alias to the `result_type` member `typedef` of `is_addable`. + /// Used to determine the type of the returned result of invoking the addition + /// operator (i.e. `operator+`) with a `TLhs` and `TRhs`, + /// i.e. `decltype(std::declval() + std::declval())` + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_addable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the addition operator (i.e. `operator+`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_addable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template using add_result_t = typename is_addable::result_type; + /// @brief Type trait to determine if `TLhs` and `TRhs` are subtractable. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` and `TRhs` are subtractable, also provides the member + /// `typedef` type `result_type` equal to the type of the returned result + /// of invoking the associated `operator-` overload, i.e. + /// `decltype(std::declval() - std::declval())`. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_subtractable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the subtraction operator (i.e. `operator-`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_subtractable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template struct is_subtractable : std::false_type { using result_type = void; }; template - requires requires(const TLhs& lhs, const TRhs& rhs) { - lhs - rhs; - rhs - lhs; - } + requires concepts::Subtractable struct is_subtractable : std::true_type { using result_type = decltype(std::declval() - std::declval()); }; + /// @brief Value of the type trait `is_subtractable` . + /// Used to determine if `TLhs` and `TRhs` are subtractable. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the subtraction operator (i.e. `operator-`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_subtractable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template static inline constexpr auto is_subtractable_v = is_subtractable::value; + /// @brief Alias to the `result_type` member `typedef` of `is_subtractable`. + /// Used to determine the type of the returned result of invoking the subtraction + /// operator (i.e. `operator-`) with a `TLhs` and `TRhs`, + /// i.e. `decltype(std::declval() - std::declval())` + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_subtractable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the subtraction operator (i.e. `operator-`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_subtractable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template using subtract_result_t = typename is_subtractable::result_type; + /// @brief Type trait to determine if `TLhs` and `TRhs` are multipliable. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` and `TRhs` are multipliable, also provides the member + /// `typedef` type `result_type` equal to the type of the returned result + /// of invoking the associated `operator*` overload, i.e. + /// `decltype(std::declval() * std::declval())`. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_multipliable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the multiplication operator (i.e. `operator*`) overload associated + /// with `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_multipliable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template struct is_multipliable : std::false_type { using result_type = void; }; template - requires requires(const TLhs& lhs, const TRhs& rhs) { - lhs* rhs; - rhs* lhs; - } + requires concepts::Multipliable struct is_multipliable : std::true_type { using result_type = decltype(std::declval() * std::declval()); }; + /// @brief Value of the type trait `is_multipliable` . + /// Used to determine if `TLhs` and `TRhs` are multipliable. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the multiplication operator (i.e. `operator*`) overload associated + /// with `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_multipliable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template static inline constexpr auto is_multipliable_v = is_multipliable::value; + /// @brief Alias to the `result_type` member `typedef` of `is_multipliable`. + /// Used to determine the type of the returned result of invoking the multiplication + /// operator (i.e. `operator*`) with a `TLhs` and `TRhs`, + /// i.e. `decltype(std::declval() * std::declval())` + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_multipliable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the multiplication operator (i.e. `operator*`) overload associated + /// with `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_multipliable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template using multiply_result_t = typename is_multipliable::result_type; + /// @brief Type trait to determine if `TLhs` and `TRhs` are dividible. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` and `TRhs` are dividible, also provides the member + /// `typedef` type `result_type` equal to the type of the returned result + /// of invoking the associated `operator/` overload, i.e. + /// `decltype(std::declval() / std::declval())`. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_dividible::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the division operator (i.e. `operator/`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_dividible` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template struct is_dividible : std::false_type { using result_type = void; }; template - requires requires(const TLhs& lhs, const TRhs& rhs) { - lhs / rhs; - rhs / lhs; - } + requires concepts::Dividible struct is_dividible : std::true_type { using result_type = decltype(std::declval() / std::declval()); }; + /// @brief Value of the type trait `is_dividible` . + /// Used to determine if `TLhs` and `TRhs` are dividible. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the division operator (i.e. `operator/`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_dividible` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template static inline constexpr auto is_dividible_v = is_dividible::value; + /// @brief Alias to the `result_type` member `typedef` of `is_dividible`. + /// Used to determine the type of the returned result of invoking the division + /// operator (i.e. `operator/`) with a `TLhs` and `TRhs`, + /// i.e. `decltype(std::declval() / std::declval())` + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_dividible::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the division operator (i.e. `operator/`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_dividible` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template using divide_result_t = typename is_dividible::result_type; + /// @brief Type trait to determine if `TLhs` and `TRhs` are binary andable. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` and `TRhs` are binary andable, also provides the member + /// `typedef` type `result_type` equal to the type of the returned result + /// of invoking the associated `operator&` overload, i.e. + /// `decltype(std::declval() & std::declval())`. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_binary_andable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the binary and operator (i.e. `operator&`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_binary_andable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template struct is_binary_andable : std::false_type { using result_type = void; }; template - requires requires(const TLhs& lhs, const TRhs& rhs) { - lhs & rhs; - rhs & lhs; - } + requires concepts::BinaryAndable struct is_binary_andable : std::true_type { using result_type = decltype(std::declval() & std::declval()); }; + /// @brief Value of the type trait `is_binary_andable` . + /// Used to determine if `TLhs` and `TRhs` are binary andable. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the binary and operator (i.e. `operator&`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_binary_andable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template static inline constexpr auto is_binary_andable_v = is_binary_andable::value; + /// @brief Alias to the `result_type` member `typedef` of `is_binary_andable`. + /// Used to determine the type of the returned result of invoking the binary and + /// operator (i.e. `operator&`) with a `TLhs` and `TRhs`, + /// i.e. `decltype(std::declval() & std::declval())` + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_binary_andable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the binary and operator (i.e. `operator&`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_binary_andable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template using binary_and_result_t = typename is_binary_andable::result_type; + /// @brief Type trait to determine if `TLhs` and `TRhs` are binary orable. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` and `TRhs` are binary orable, also provides the member + /// `typedef` type `result_type` equal to the type of the returned result + /// of invoking the associated `operator|` overload, i.e. + /// `decltype(std::declval() | std::declval())`. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_binary_orable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the binary or operator (i.e. `operator|`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_binary_orable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template struct is_binary_orable : std::false_type { using result_type = void; }; template - requires requires(const TLhs& lhs, const TRhs& rhs) { - lhs | rhs; - rhs | lhs; - } + requires concepts::BinaryOrable struct is_binary_orable : std::true_type { using result_type = decltype(std::declval() | std::declval()); }; + /// @brief Value of the type trait `is_binary_orable` . + /// Used to determine if `TLhs` and `TRhs` are binary orable. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the binary or operator (i.e. `operator|`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_binary_orable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template static inline constexpr auto is_binary_orable_v = is_binary_orable::value; + /// @brief Alias to the `result_type` member `typedef` of `is_binary_orable`. + /// Used to determine the type of the returned result of invoking the binary or + /// operator (i.e. `operator|`) with a `TLhs` and `TRhs`, + /// i.e. `decltype(std::declval() | std::declval())` + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_binary_orable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the binary or operator (i.e. `operator|`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_binary_orable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template using binary_or_result_t = typename is_binary_orable::result_type; + /// @brief Type trait to determine if `TLhs` and `TRhs` are boolean andable. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` and `TRhs` are boolean andable, also provides the member + /// `typedef` type `result_type` equal to the type of the returned result + /// of invoking the associated `operator&&` overload, i.e. + /// `decltype(std::declval() && std::declval())`. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_boolean_andable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the boolean and operator (i.e. `operator&&`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_boolean_andable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template struct is_boolean_andable : std::false_type { using result_type = void; }; template - requires requires(const TLhs& lhs, const TRhs& rhs) { - lhs&& rhs; - rhs&& lhs; - } + requires concepts::BooleanAndable struct is_boolean_andable : std::true_type { using result_type = decltype(std::declval() && std::declval()); }; + /// @brief Value of the type trait `is_boolean_andable` . + /// Used to determine if `TLhs` and `TRhs` are boolean andable. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the boolean and operator (i.e. `operator&&`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_boolean_andable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template static inline constexpr auto is_boolean_andable_v = is_boolean_andable::value; + /// @brief Alias to the `result_type` member `typedef` of `is_boolean_andable`. + /// Used to determine the type of the returned result of invoking the boolean and + /// operator (i.e. `operator&&`) with a `TLhs` and `TRhs`, + /// i.e. `decltype(std::declval() && std::declval())` + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_boolean_andable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the boolean and operator (i.e. `operator&&`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_boolean_andable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template using boolean_and_result_t = typename is_boolean_andable::result_type; + /// @brief Type trait to determine if `TLhs` and `TRhs` are boolean orable. + /// + /// In addition to providing the static member `value`, indicating + /// whether a `TLhs` and `TRhs` are boolean orable, also provides the member + /// `typedef` type `result_type` equal to the type of the returned result + /// of invoking the associated `operator||` overload, i.e. + /// `decltype(std::declval() || std::declval())`. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_boolean_orable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the boolean or operator (i.e. `operator||`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_boolean_orable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template struct is_boolean_orable : std::false_type { using result_type = void; }; template - requires requires(const TLhs& lhs, const TRhs& rhs) { - lhs || rhs; - rhs || lhs; - } + requires concepts::BooleanOrable struct is_boolean_orable : std::true_type { using result_type = decltype(std::declval() || std::declval()); }; + /// @brief Value of the type trait `is_boolean_orable` . + /// Used to determine if `TLhs` and `TRhs` are boolean orable. + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the boolean or operator (i.e. `operator||`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_boolean_orable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template static inline constexpr auto is_boolean_orable_v = is_boolean_orable::value; + /// @brief Alias to the `result_type` member `typedef` of `is_boolean_orable`. + /// Used to determine the type of the returned result of invoking the boolean or + /// operator (i.e. `operator||`) with a `TLhs` and `TRhs`, + /// i.e. `decltype(std::declval() || std::declval())` + /// + /// @tparam TLhs The type of the left-hand parameter + /// @tparam TRhs The type of the right-hand parameter. Defaults to `TLhs` + /// @ingroup general_operator_detection + /// @headerfile hyperion/mpl/type_traits/is_operator_able.h + /// + /// @note Presence of `result_type` should not be used as a short-hand + /// or alternaitve to checking `value` in any way + /// (e.g. in a SFINAE-compatible context or C++20 `requires` clause): + /// if `is_boolean_orable::value == false`, + /// then `result_type` will be `void` + /// + /// @note Due to overloadability by cv-ref qualification, care should be taken + /// to ensure that use of `result_type` (and this trait in general) is + /// associated with the correct cv-ref qualification(s) of the unqualified types + /// of `TLhs` and `TRhs`. I.E., given types `TType1` and `TType2`, if you intend + /// to invoke the boolean or operator (i.e. `operator||`) overload associated with + /// `TType1` and `TType2` with `const TType1&` and `const TType2&`, make sure + /// sure that you instantiate and use `is_boolean_orable` with `TLhs = const TType1&` + /// and `TRhs = const TType2&`, not `TType1`, `TType2&` or any other + /// qualification of either type thereof. template using boolean_or_result_t = typename is_boolean_orable::result_type; diff --git a/xmake.lua b/xmake.lua index 4b0dfdb..9948868 100644 --- a/xmake.lua +++ b/xmake.lua @@ -41,6 +41,9 @@ option("hyperion_enable_tracy", function() end) end) +local hyperion_mpl_main_header = { + "$(projectdir)/include/hyperion/mpl.h", +} local hyperion_mpl_headers = { "$(projectdir)/include/hyperion/mpl/algorithms.h", "$(projectdir)/include/hyperion/mpl/concepts.h", @@ -67,6 +70,7 @@ target("hyperion_mpl", function() set_kind("headeronly") set_languages("cxx20") add_includedirs("$(projectdir)/include", { public = true }) + add_headerfiles(hyperion_mpl_main_header, { prefixdir = "hyperion", public = true }) add_headerfiles(hyperion_mpl_headers, { prefixdir = "hyperion/mpl", public = true }) add_headerfiles(hyperion_mpl_algorithms_headers, { prefixdir = "hyperion/mpl/algorithms", public = true }) add_headerfiles(hyperion_mpl_concepts_headers, { prefixdir = "hyperion/mpl/concepts", public = true })