diff --git a/include/stdx/ct_string.hpp b/include/stdx/ct_string.hpp index ce9bff3..8bb42bc 100644 --- a/include/stdx/ct_string.hpp +++ b/include/stdx/ct_string.hpp @@ -242,5 +242,10 @@ template // NOLINTNEXTLINE(*-avoid-c-arrays) map_value_helper(char const (&)[N]) -> map_value_helper>; } // namespace detail + +template +consteval auto shrink() -> decltype(detail::shrink()) { + return {}; +} } // namespace v1 } // namespace stdx diff --git a/include/stdx/type_traits.hpp b/include/stdx/type_traits.hpp index e35b729..99ed0fc 100644 --- a/include/stdx/type_traits.hpp +++ b/include/stdx/type_traits.hpp @@ -223,8 +223,16 @@ template struct shrinkwrap { using type = T; }; +template struct shrinkwrap_value { + using is_shrinkwrapped_value = void; + constexpr static auto value = V; +}; + template concept is_shrinkwrapped = requires { typename T::is_shrinkwrapped; }; +template +concept is_shrinkwrapped_value = + requires { typename T::is_shrinkwrapped_value; }; template auto (*)() -> shrinkwrap { return nullptr; }> @@ -232,11 +240,22 @@ consteval auto shrink() { return F; } +template auto (*)() -> shrinkwrap_value { return nullptr; }> +consteval auto shrink() { + return F; +} + template concept is_shrunk = requires(T const &t) { { t()() } -> is_shrinkwrapped; }; +template +concept is_shrunk_value = requires(T const &t) { + { t()() } -> is_shrinkwrapped_value; +}; + template consteval auto maybe_expand() -> T; template consteval auto maybe_expand() -> typename decltype(T{}()())::type; @@ -257,6 +276,10 @@ constexpr auto maybe_expand(T &&) -> "object: use expand_t{} instead if this is what you want"); return R{}; } +template constexpr auto maybe_expand(T &&) { + using R = decltype(std::remove_cvref_t{}()()); + return R::value; +} } // namespace detail template consteval auto shrink() -> decltype(detail::shrink()) { diff --git a/test/type_traits.cpp b/test/type_traits.cpp index ecffbce..ab6ee4e 100644 --- a/test/type_traits.cpp +++ b/test/type_traits.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -244,6 +245,12 @@ TEST_CASE("type shrinkage (by type)", "[type_traits]") { STATIC_CHECK(std::is_same_v, C>); } +TEST_CASE("two shrunk types are considered the same", "[type_traits]") { + using X = stdx::shrink_t; + using Y = stdx::shrink_t; + STATIC_CHECK(std::is_same_v); +} + TEST_CASE("type shrinkage (by value)", "[type_traits]") { auto c = C{}; auto x = stdx::shrink(c); @@ -253,6 +260,35 @@ TEST_CASE("type shrinkage (by value)", "[type_traits]") { STATIC_CHECK(std::is_same_v); } +TEST_CASE("value shrinkage for ct_strings", "[type_traits]") { + using namespace stdx::literals; + constexpr auto x = stdx::shrink<"hello"_cts>(); + constexpr auto y = stdx::expand(x); + STATIC_CHECK(y == "hello"_cts); +} + +TEST_CASE("two shrunk ct_strings are considered the same type", + "[type_traits]") { + constexpr auto x = stdx::shrink<"hello">(); + constexpr auto y = stdx::shrink<"hello">(); + STATIC_CHECK(std::is_same_v); +} + +namespace { +template consteval auto return_expanded() { return stdx::expand(T); } +} // namespace + +TEST_CASE("pass shrunk ct_string as template argument", "[type_traits]") { + using namespace stdx::literals; + STATIC_CHECK(return_expanded()>() == "hello"_cts); +} + +TEST_CASE("non-shrunk value can be expanded (with no effect)", + "[type_traits]") { + constexpr auto x = stdx::expand(42); + STATIC_CHECK(x == 42); +} + TEST_CASE("nth type in pack", "[type_traits]") { STATIC_REQUIRE( std::is_same_v, float>);