Skip to content

Commit f8d8a60

Browse files
committed
🎨 Adjust type shrink/expand functions
Problem: - Sometimes it would be more convenient to call `shrink(x)` or `expand(y)` with existing values rather than using e.g. `shrink_t<std::remove_cvref_t<decltype(x)>>` and the `expand_t` equivalent. Solution: - Add appropriate `shrink` and `expand` functions.
1 parent 2b1e4a3 commit f8d8a60

2 files changed

Lines changed: 67 additions & 11 deletions

File tree

include/stdx/type_traits.hpp

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,22 +244,67 @@ CONSTEVAL auto shrink() {
244244
}
245245

246246
template <typename T>
247-
concept is_shrunk = requires(T t) {
247+
concept is_shrunk = requires(T const &t) {
248248
{ t()() } -> is_shrinkwrapped;
249249
};
250250

251251
template <typename T> CONSTEVAL auto maybe_expand() -> T;
252252
template <is_shrunk T>
253253
CONSTEVAL auto maybe_expand() -> typename decltype(T{}()())::type;
254+
255+
template <typename T> CONSTEVAL auto maybe_expand(T &&t) -> decltype(auto) {
256+
return T(std::forward<T>(t));
257+
}
258+
template <is_shrunk T>
259+
CONSTEVAL auto maybe_expand(T &&) ->
260+
typename decltype(std::remove_cvref_t<T>{}()())::type {
261+
using R = typename decltype(std::remove_cvref_t<T>{}()())::type;
262+
static_assert(std::is_default_constructible_v<R>,
263+
"expand(T) cannot default-construct the return value: maybe "
264+
"use expand_t<T> instead?");
265+
return R{};
266+
}
254267
} // namespace detail
255268

256-
template <typename T> CONSTEVAL auto shrink() -> decltype(detail::shrink<T>());
269+
template <typename T> CONSTEVAL auto shrink() -> decltype(detail::shrink<T>()) {
270+
static_assert(
271+
always_false_v<T>,
272+
"shrink<T>() should not be called outside an unevaluated context");
273+
}
274+
template <typename T>
275+
CONSTEVAL auto shrink(T) -> decltype(detail::shrink<T>()) {
276+
return {};
277+
}
257278

258279
template <typename T>
259-
CONSTEVAL auto expand() -> decltype(detail::maybe_expand<T>());
280+
CONSTEVAL auto expand() -> decltype(detail::maybe_expand<T>()) {
281+
using R = decltype(detail::maybe_expand<T>());
282+
static_assert(
283+
always_false_v<R>,
284+
"expand<T>() should not be called outside an unevaluated context");
285+
}
286+
template <typename T> CONSTEVAL auto expand(T &&t) -> decltype(auto) {
287+
return detail::maybe_expand(std::forward<T>(t));
288+
}
289+
260290
#else
261-
template <typename T> CONSTEVAL auto shrink() -> T;
262-
template <typename T> CONSTEVAL auto expand() -> T;
291+
template <typename T> CONSTEVAL auto shrink() -> T {
292+
static_assert(
293+
always_false_v<T>,
294+
"shrink<T>() should not be called outside an unevaluated context");
295+
}
296+
template <typename T> CONSTEVAL auto shrink(T &&t) -> decltype(auto) {
297+
return T(std::forward<T>(t));
298+
}
299+
300+
template <typename T> CONSTEVAL auto expand() -> T {
301+
static_assert(
302+
always_false_v<T>,
303+
"expand<T>() should not be called outside an unevaluated context");
304+
}
305+
template <typename T> CONSTEVAL auto expand(T &&t) -> decltype(auto) {
306+
return T(std::forward<T>(t));
307+
}
263308
#endif
264309

265310
template <typename T> using shrink_t = decltype(shrink<T>());

test/type_traits.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -245,21 +245,32 @@ TEST_CASE("non-structural types", "[type_traits]") {
245245
STATIC_REQUIRE(not stdx::is_structural_v<non_structural::S>);
246246
}
247247

248-
#if __cplusplus >= 202002L
249248
namespace {
250249
template <typename...> struct long_type_name {};
250+
using A = long_type_name<int, int, int, int, int, int, int, int>;
251+
using B = long_type_name<A, A, A, A, A, A, A, A>;
252+
using C = long_type_name<B, B, B, B, B, B, B, B>;
251253
} // namespace
252254

253-
TEST_CASE("type shrinkage", "[type_traits]") {
254-
using A = long_type_name<int, int, int, int, int, int, int, int>;
255-
using B = long_type_name<A, A, A, A, A, A, A, A>;
256-
using C = long_type_name<B, B, B, B, B, B, B, B>;
255+
TEST_CASE("type shrinkage (by type)", "[type_traits]") {
257256
using X = stdx::shrink_t<C>;
257+
#if __cplusplus >= 202002L
258258
STATIC_CHECK(stdx::type_as_string<X>().size() <
259259
stdx::type_as_string<C>().size());
260-
STATIC_CHECK(std::same_as<stdx::expand_t<X>, C>);
260+
#endif
261+
STATIC_CHECK(std::is_same_v<stdx::expand_t<X>, C>);
261262
}
263+
264+
TEST_CASE("type shrinkage (by value)", "[type_traits]") {
265+
auto c = C{};
266+
auto x = stdx::shrink(c);
267+
auto y = stdx::expand(x);
268+
#if __cplusplus >= 202002L
269+
STATIC_CHECK(stdx::type_as_string<decltype(x)>().size() <
270+
stdx::type_as_string<C>().size());
262271
#endif
272+
STATIC_CHECK(std::is_same_v<decltype(y), C>);
273+
}
263274

264275
TEST_CASE("nth type in pack", "[type_traits]") {
265276
STATIC_REQUIRE(

0 commit comments

Comments
 (0)