Skip to content

Commit 2e5c17f

Browse files
authored
Merge pull request #246 from elbeno/upgrade-static-assert-format
🎨 Improve `STATIC_ASSERT`
2 parents 3641035 + 1972ba2 commit 2e5c17f

File tree

5 files changed

+72
-26
lines changed

5 files changed

+72
-26
lines changed

docs/ct_format.adoc

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11

22
== `ct_format.hpp`
33

4+
=== ct_format
5+
46
https://github.com/intel/cpp-std-extensions/blob/main/include/stdx/ct_format.hpp[`ct_format.hpp`]
57
provides `ct_format`, a compile-time function for formatting strings.
68

@@ -20,7 +22,7 @@ auto s = stdx::ct_format<"Hello {} {}">(42, 17);
2022
----
2123

2224
When format arguments are available at compile-time, wrapping them in
23-
`CX_VALUE(...)` means they will get compile-time formatted.
25+
xref:utility.adoc#_cx_value[`CX_VALUE(...)`] means they will get compile-time formatted.
2426
[source,cpp]
2527
----
2628
auto s = stdx::ct_format<"Hello {} {}">(CX_VALUE(42), 17);
@@ -69,3 +71,31 @@ constexpr static auto a = stdx::ct_format<"The answer is {}">(42);
6971
constexpr static auto q = stdx::ct_format<"{}. But what is the question?">(CX_VALUE(a));
7072
// q is stdx::format_result{"The answer is {}. But what is the question?"_ctst, stdx::tuple{42}}
7173
----
74+
75+
=== STDX_CT_FORMAT
76+
77+
The macro `STDX_CT_FORMAT` will automatically wrap compile-time-friendly
78+
arguments, so manual wrapping with `CX_VALUE` is not required.
79+
[source,cpp]
80+
----
81+
auto s = STDX_CT_FORMAT("Hello {} {}", 42, int);
82+
// equivalent to stdx::ct_format<"Hello {} {}">(CX_VALUE(42), CX_VALUE(int));
83+
// s is stdx::format_result{"Hello 42 int"_ctst, stdx::tuple{}}
84+
----
85+
86+
If any arguments are _not_ available at compile time, they will be "regular" runtime format arguments.
87+
[source,cpp]
88+
----
89+
auto x = 42;
90+
auto s = STDX_CT_FORMAT("Hello {} {}", x, int);
91+
// equivalent to stdx::ct_format<"Hello {} {}">(x, CX_VALUE(int));
92+
// s is stdx::format_result{"Hello {} int"_ctst, stdx::tuple{42}}
93+
----
94+
95+
Things that are "compile-time-friendly" include:
96+
97+
* `constexpr static` variables
98+
* `const` integral variables
99+
* template arguments
100+
* literals
101+
* types

docs/ct_string.adoc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,19 @@ constexpr auto s = "hello"_ctst;
9797
// s is a stdx::cts_t<"hello">
9898
----
9999
Think of `cts_t` relating to `ct_string` as `std::integral_constant` relates to `int`.
100+
101+
A `cts_t` is implicitly convertible to a `ct_string`, or can be explicitly
102+
converted with unary `operator+`:
103+
104+
105+
[source,cpp]
106+
----
107+
using namespace stdx::literals;
108+
109+
template <stdx::ct_string S>
110+
constexpr bool always_true = true;
111+
112+
constexpr auto s = "hello"_ctst;
113+
static_assert(always_true<s>); // implicit conversion
114+
static_assert(always_true<+s>); // explicit conversion with +
115+
----

docs/static_assert.adoc

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,13 @@
88
template <typename T>
99
constexpr auto f() {
1010
STATIC_ASSERT(std::is_integral<T>,
11-
"f() must take an integral type, received {}", CX_VALUE(T));
11+
"f() must take an integral type, received {}", T);
1212
}
1313
1414
f<float>(); // produces compile-time error
1515
----
1616

17-
The arguments to be formatted (if any) must be wrapped in
18-
xref:utility.adoc#_cx_value[`CX_VALUE`] if they are not admissible as template
19-
arguments.
17+
NOTE: The arguments to be formatted must be compile-time, of course.
2018

2119
The output from this (which varies by compiler) will contain the formatted
2220
string, and could be something like:
@@ -33,3 +31,15 @@ include/stdx/static_assert.hpp:16:18: note: because
3331

3432
NOTE: clang produces these "string-formatted" errors from version 15 onwards; GCC
3533
produces them from version 13.2 onwards.
34+
35+
After C++26,
36+
https://en.cppreference.com/w/cpp/language/static_assert.html[`static_assert`]
37+
in the language means that formatted `STATIC_ASSERT` produces a slightly nicer
38+
error message; something like:
39+
40+
[source,bash]
41+
----
42+
main.cpp:14:27: error: static assertion failed: f() must take an integral type, received float
43+
16 | STATIC_ASSERT(std::is_integral<T>,
44+
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
45+
----

include/stdx/static_assert.hpp

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,41 +22,31 @@ template <> struct ct_check_t<true> {
2222
}
2323
};
2424
template <bool B> constexpr auto ct_check = ct_check_t<B>{};
25-
26-
namespace detail {
27-
template <ct_string Fmt, auto... Args> constexpr auto static_format() {
28-
constexpr auto make_ct = []<auto V>() {
29-
if constexpr (fmt_cx_value<decltype(V)>) {
30-
return V;
31-
} else {
32-
return CX_VALUE(V);
33-
}
34-
};
35-
return ct_format<Fmt>(make_ct.template operator()<Args>()...).str.value;
36-
}
37-
} // namespace detail
38-
3925
} // namespace v1
4026
} // namespace stdx
4127

4228
#if __cpp_static_assert >= 202306L
29+
4330
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
4431
#define STATIC_ASSERT(cond, ...) \
4532
[]<bool B>() -> bool { \
4633
STDX_PRAGMA(diagnostic push) \
4734
STDX_PRAGMA(diagnostic ignored "-Wunknown-warning-option") \
4835
STDX_PRAGMA(diagnostic ignored "-Wc++26-extensions") \
49-
static_assert( \
50-
B, std::string_view{stdx::detail::static_format<__VA_ARGS__>()}); \
36+
constexpr auto S = STDX_CT_FORMAT(__VA_ARGS__); \
37+
static_assert(B, std::string_view{+S.str}); \
5138
STDX_PRAGMA(diagnostic pop) \
5239
return B; \
5340
}.template operator()<cond>()
41+
5442
#else
43+
5544
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
56-
#define STATIC_ASSERT(cond, ...) \
57-
[]<bool B>() -> bool { \
58-
stdx::ct_check<B>.template emit<stdx::detail::static_format<__VA_ARGS__>()>(); \
59-
return B; \
45+
#define STATIC_ASSERT(cond, ...) \
46+
[]<bool B>() -> bool { \
47+
constexpr auto S = STDX_CT_FORMAT(__VA_ARGS__); \
48+
stdx::ct_check<B>.template emit<S>(); \
49+
return B; \
6050
}.template operator()<cond>()
6151
#endif
6252

test/fail/static_assert_format.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// EXPECT: hello world int 123
55

66
template <typename T> constexpr auto f() {
7-
STATIC_ASSERT(false, "hello {} {} {}", CX_VALUE("world"), CX_VALUE(T), 123);
7+
STATIC_ASSERT(false, "hello {} {} {}", "world", T, 123);
88
}
99

1010
auto main() -> int { f<int>(); }

0 commit comments

Comments
 (0)