Skip to content

Commit 01d335d

Browse files
committed
✨ Add CT_WRAP
Problem: - It is useful to have a macro that wraps a potentially-`constexpr`-usable value in `stdx::ct` when possible, to preserve its `constexpr` properties. Solution: - Add `CT_WRAP` that does this. Notes: - See intel/compile-time-init-build#743 for some parts of this in CIB; this part probably belongs in stdx.
1 parent effadd4 commit 01d335d

File tree

4 files changed

+86
-0
lines changed

4 files changed

+86
-0
lines changed

include/stdx/ct_string.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ template <std::size_t N> struct ct_helper<ct_string<N>>;
160160

161161
template <ct_string Value> CONSTEVAL auto ct() { return cts_t<Value>{}; }
162162

163+
template <ct_string Value> constexpr auto is_ct_v<cts_t<Value>> = true;
164+
163165
inline namespace literals {
164166
inline namespace ct_string_literals {
165167
template <ct_string S> CONSTEVAL_UDL auto operator""_cts() { return S; }

include/stdx/utility.hpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,12 @@ template <detail::ct_helper Value> CONSTEVAL auto ct() {
209209
}
210210
template <typename T> CONSTEVAL auto ct() { return type_identity<T>{}; }
211211

212+
template <typename> constexpr auto is_ct_v = false;
213+
template <typename T, T V>
214+
constexpr auto is_ct_v<std::integral_constant<T, V>> = true;
215+
template <typename T> constexpr auto is_ct_v<type_identity<T>> = true;
216+
template <typename T> constexpr auto is_ct_v<T const> = is_ct_v<T>;
217+
212218
#endif
213219
} // namespace v1
214220
} // namespace stdx
@@ -244,5 +250,22 @@ template <typename T> CONSTEVAL auto ct() { return type_identity<T>{}; }
244250
}()
245251
#endif
246252

253+
#if __cplusplus >= 202002L
254+
255+
#define CT_WRAP(X) \
256+
[&](auto f) { \
257+
if constexpr (::stdx::is_ct_v<decltype(f())>) { \
258+
return f(); \
259+
} else if constexpr (requires { \
260+
::stdx::ct<[&]() constexpr { return X; }()>; \
261+
}) { \
262+
return ::stdx::ct<[&]() constexpr { return X; }()>(); \
263+
} else { \
264+
return f(); \
265+
} \
266+
}([&] { return X; })
267+
268+
#endif
269+
247270
// NOLINTEND(cppcoreguidelines-macro-usage)
248271
// NOLINTEND(modernize-use-constraints)

test/ct_string.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,30 @@ TEST_CASE("ct (ct_string)", "[ct_string]") {
150150
constexpr auto v2 = stdx::ct<"Hello"_cts>();
151151
STATIC_REQUIRE(v2 == "Hello"_ctst);
152152
}
153+
154+
TEST_CASE("is_ct (ct_string)", "[ct_string]") {
155+
using namespace stdx::ct_string_literals;
156+
constexpr auto v1 = stdx::ct<"Hello">();
157+
STATIC_REQUIRE(stdx::is_ct_v<decltype(v1)>);
158+
}
159+
160+
TEST_CASE("CT_WRAP", "[ct_string]") {
161+
using namespace stdx::ct_string_literals;
162+
auto x1 = "hello"_cts;
163+
STATIC_REQUIRE(std::is_same_v<decltype(CT_WRAP(x1)), stdx::ct_string<6>>);
164+
CHECK(CT_WRAP(x1) == "hello"_cts);
165+
166+
auto x2 = "hello"_ctst;
167+
STATIC_REQUIRE(std::is_same_v<decltype(CT_WRAP(x2)), stdx::cts_t<"hello">>);
168+
STATIC_REQUIRE(CT_WRAP(x2) == "hello"_ctst);
169+
170+
constexpr static auto x3 = "hello"_cts;
171+
STATIC_REQUIRE(std::is_same_v<decltype(CT_WRAP(x3)), stdx::cts_t<"hello">>);
172+
STATIC_REQUIRE(CT_WRAP(x3) == "hello"_ctst);
173+
174+
[]<stdx::ct_string X>() {
175+
STATIC_REQUIRE(
176+
std::is_same_v<decltype(CT_WRAP(X)), stdx::cts_t<"hello">>);
177+
STATIC_REQUIRE(CT_WRAP(X) == "hello"_ctst);
178+
}.template operator()<"hello">();
179+
}

test/utility.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,4 +271,38 @@ TEST_CASE("ct (type)", "[utility]") {
271271
STATIC_REQUIRE(std::is_same_v<decltype(v), stdx::type_identity<int> const>);
272272
}
273273

274+
TEST_CASE("is_ct", "[utility]") {
275+
constexpr auto x1 = stdx::ct<42>();
276+
STATIC_REQUIRE(stdx::is_ct_v<decltype(x1)>);
277+
constexpr auto x2 = stdx::ct<int>();
278+
STATIC_REQUIRE(stdx::is_ct_v<decltype(x2)>);
279+
}
280+
281+
TEST_CASE("CT_WRAP", "[utility]") {
282+
auto x1 = 42;
283+
STATIC_REQUIRE(std::is_same_v<decltype(CT_WRAP(x1)), int>);
284+
CHECK(CT_WRAP(x1) == 42);
285+
286+
auto x2 = stdx::ct<42>();
287+
STATIC_REQUIRE(
288+
std::is_same_v<decltype(CT_WRAP(x2)), std::integral_constant<int, 42>>);
289+
STATIC_REQUIRE(CT_WRAP(x2).value == 42);
290+
291+
auto const x3 = 42;
292+
STATIC_REQUIRE(
293+
std::is_same_v<decltype(CT_WRAP(x3)), std::integral_constant<int, 42>>);
294+
STATIC_REQUIRE(CT_WRAP(x3).value == 42);
295+
296+
constexpr static auto x4 = 42;
297+
STATIC_REQUIRE(
298+
std::is_same_v<decltype(CT_WRAP(x4)), std::integral_constant<int, 42>>);
299+
STATIC_REQUIRE(CT_WRAP(x4).value == 42);
300+
301+
[]<auto X>() {
302+
STATIC_REQUIRE(std::is_same_v<decltype(CT_WRAP(X)),
303+
std::integral_constant<int, 42>>);
304+
STATIC_REQUIRE(CT_WRAP(X).value == 42);
305+
}.template operator()<42>();
306+
}
307+
274308
#endif

0 commit comments

Comments
 (0)