From e974b9d43d4d6bbaeb5b648c8ba2cb0d899b79b8 Mon Sep 17 00:00:00 2001 From: Christos Houtouridis Date: Sun, 13 Oct 2019 19:52:54 +0300 Subject: [PATCH] meta: Detection idiom (part 1) from Walter Brown added --- include/utl/meta/detection.h | 112 ++++++++++++++++++++++++++++++++++- include/utl/meta/invoke.h | 2 +- include/utl/meta/meta.h | 3 +- include/utl/meta/typelist.h | 2 +- test/tests/Tmeta.cpp | 4 +- 5 files changed, 116 insertions(+), 7 deletions(-) diff --git a/include/utl/meta/detection.h b/include/utl/meta/detection.h index 0ee292c..4135b5f 100644 --- a/include/utl/meta/detection.h +++ b/include/utl/meta/detection.h @@ -55,7 +55,117 @@ namespace meta { template using void_t = void; #endif //! @} + + /*! + * Not a type to use in detected idiom + */ + struct nat_ { + nat_() = delete; + ~nat_() = delete; + nat_(nat_ const&) = delete; + void operator = (nat_ const&) = delete; + }; + + //! Detector for detection idiom + //! @{ + namespace detail { + template class Op, typename... Args> + struct detector { + using detected = false_; + using type = Default; + }; + + template class Op, typename... Args> + struct detector >, Op, Args...> { + using detected = true_; + using type = Op; + }; + + //! helper for detected_or_t + template class Op, typename... Args> + using detected_or = detector; + } // namespace detail + //! @} + + /*! + * detection interface + */ + //! @{ + + /*! + * Checks if Op is a valid expression without evaluating it. + * + * \param Op a meta-callback function to pass Args... + * \param Args... types to pass to Op for checking + * \return status of the operation [bool_] + * \arg true_ if Op is valid expression + * \arg false_ if Op is not valid + * + * \example + * \code + * // archetypal alias for a copy assignment operation + * template< class T > + * using copy_assign_t = decltype( declval() = declval() ); + * + * template< class T > + * using is_copy_assignable = is_detected< T, copy_assign_t >; + * \endcode + */ + template class Op, typename... Args> + using is_detected = typename detail::detector::detected; + + //! Detection predicate + template< template class Op, typename... Args> + constexpr bool is_detected_v = is_detected::value; + //! @} + + /*! + * Detection idiom toolkit + */ + //! @{ + + //! evaluates to evaluation of Op if it's valid and to nat_ if not + template class Op, typename... Args> + using detected_t = eval < + detail::detector + >; + + //! evaluates to evaluation of Op if it's valid and to \p Default if not + template class Op, typename... Args> + using detected_or_t = eval < + detail::detected_or + >; + + //! evaluates to true_ if evaluation of Op is \p Expected and to false_ if not + template class Op, typename... Args > + using is_detected_exact = same_ >; + + //! evaluates to true if evaluation of Op is \p Expected and to false if not + template class Op, typename... Args > + constexpr bool is_detected_exact_v = is_detected_exact< Expected, Op, Args...>::value; + + //! evaluates to true_ if evaluation of Op is convertible to \p To + //! and to false_ if not + template class Op, typename... Args > + using is_detected_convertible = std::is_convertible< detected_t, To >; + + //! evaluates to true if evaluation of Op is convertible to \p To + //! and to false if not + template class Op, typename... Args > + constexpr bool is_detected_convertible_v = + is_detected_convertible::value; + //! @} + }} //!@} -#endif /* __utl_meta_void_h__ */ +#endif /* __utl_meta_detection_h__ */ diff --git a/include/utl/meta/invoke.h b/include/utl/meta/invoke.h index 020c4f1..586d18d 100644 --- a/include/utl/meta/invoke.h +++ b/include/utl/meta/invoke.h @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include diff --git a/include/utl/meta/meta.h b/include/utl/meta/meta.h index 27218a9..aedd778 100644 --- a/include/utl/meta/meta.h +++ b/include/utl/meta/meta.h @@ -21,14 +21,13 @@ #ifndef __utl_meta_meta_h__ #define __utl_meta_meta_h__ -#include #include #include #include #include #include #include - +#include #include #endif /* __utl_meta_meta_h__ */ diff --git a/include/utl/meta/typelist.h b/include/utl/meta/typelist.h index cb66d46..23d39b4 100644 --- a/include/utl/meta/typelist.h +++ b/include/utl/meta/typelist.h @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include /*! diff --git a/test/tests/Tmeta.cpp b/test/tests/Tmeta.cpp index a05a1cb..7b252a7 100644 --- a/test/tests/Tmeta.cpp +++ b/test/tests/Tmeta.cpp @@ -160,9 +160,9 @@ namespace test_meta { } /* - * Test void + * Test void_t */ - TEST(Tmeta_void, VoidType) { + TEST(Tmeta, VoidType) { struct Foo {}; struct Bar {}; EXPECT_EQ(true, (std::is_same>()));