Skip to content

Commit 7094d81

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 5f65449 commit 7094d81

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
@@ -173,6 +173,8 @@ template <std::size_t N> struct ct_helper<ct_string<N>>;
173173

174174
template <ct_string Value> CONSTEVAL auto ct() { return cts_t<Value>{}; }
175175

176+
template <ct_string Value> constexpr auto is_ct_v<cts_t<Value>> = true;
177+
176178
inline namespace literals {
177179
inline namespace ct_string_literals {
178180
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
@@ -165,3 +165,30 @@ TEST_CASE("operator+ works to concat cts_t and ct_string", "[ct_string]") {
165165
STATIC_REQUIRE("Hello"_ctst + " world"_cts == "Hello world"_cts);
166166
STATIC_REQUIRE("Hello"_cts + " world"_ctst == "Hello world"_cts);
167167
}
168+
169+
TEST_CASE("is_ct (ct_string)", "[ct_string]") {
170+
using namespace stdx::ct_string_literals;
171+
constexpr auto v1 = stdx::ct<"Hello">();
172+
STATIC_REQUIRE(stdx::is_ct_v<decltype(v1)>);
173+
}
174+
175+
TEST_CASE("CT_WRAP", "[ct_string]") {
176+
using namespace stdx::ct_string_literals;
177+
auto x1 = "hello"_cts;
178+
STATIC_REQUIRE(std::is_same_v<decltype(CT_WRAP(x1)), stdx::ct_string<6>>);
179+
CHECK(CT_WRAP(x1) == "hello"_cts);
180+
181+
auto x2 = "hello"_ctst;
182+
STATIC_REQUIRE(std::is_same_v<decltype(CT_WRAP(x2)), stdx::cts_t<"hello">>);
183+
STATIC_REQUIRE(CT_WRAP(x2) == "hello"_ctst);
184+
185+
constexpr static auto x3 = "hello"_cts;
186+
STATIC_REQUIRE(std::is_same_v<decltype(CT_WRAP(x3)), stdx::cts_t<"hello">>);
187+
STATIC_REQUIRE(CT_WRAP(x3) == "hello"_ctst);
188+
189+
[]<stdx::ct_string X>() {
190+
STATIC_REQUIRE(
191+
std::is_same_v<decltype(CT_WRAP(X)), stdx::cts_t<"hello">>);
192+
STATIC_REQUIRE(CT_WRAP(X) == "hello"_ctst);
193+
}.template operator()<"hello">();
194+
}

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 = 17;
283+
STATIC_REQUIRE(std::is_same_v<decltype(CT_WRAP(x1)), int>);
284+
CHECK(CT_WRAP(x1) == 17);
285+
286+
auto x2 = stdx::ct<17>();
287+
STATIC_REQUIRE(
288+
std::is_same_v<decltype(CT_WRAP(x2)), std::integral_constant<int, 17>>);
289+
STATIC_REQUIRE(CT_WRAP(x2).value == 17);
290+
291+
auto const x3 = 17;
292+
STATIC_REQUIRE(
293+
std::is_same_v<decltype(CT_WRAP(x3)), std::integral_constant<int, 17>>);
294+
STATIC_REQUIRE(CT_WRAP(x3).value == 17);
295+
296+
constexpr static auto x4 = 17;
297+
STATIC_REQUIRE(
298+
std::is_same_v<decltype(CT_WRAP(x4)), std::integral_constant<int, 17>>);
299+
STATIC_REQUIRE(CT_WRAP(x4).value == 17);
300+
301+
[]<auto X>() {
302+
STATIC_REQUIRE(std::is_same_v<decltype(CT_WRAP(X)),
303+
std::integral_constant<int, 17>>);
304+
STATIC_REQUIRE(CT_WRAP(X).value == 17);
305+
}.template operator()<17>();
306+
}
307+
274308
#endif

0 commit comments

Comments
 (0)