Is there a way to print the value of a constexpr
or #define
d value at compile time? I want the equivalent of std::cout <<
, or some way to do something like
constexpr int PI_INT = 4;
static_assert(PI_INT == 3,
const_str_join("PI_INT must be 3, not ", const_int_to_str(PI_INT)));
Edit: I can do some basic compile-time printing with constexpr
s, at least on gcc by doing something like
template <int v>
struct display_non_zero_int_value;
template <>
struct display_non_zero_int_value<0> { static constexpr bool foo = true; };
static constexpr int v = 1;
static_assert(v == 0 && display_non_zero_int_value<v>::foo, "v == 0");
which gives me error: incomplete type ‘display_non_zero_int_value<1>’ used in nested name specifier static_assert(v == 0 && display_non_zero_int_value<v>::foo, "v == 0");
. (icpc, on the other hand, is less helpful, and just says error: incomplete type is not allowed
) Is there a way to write a macro that can generalize this so that I can do something like
constexpr int PI_INT = 4;
PRINT_VALUE(PI_INT)
and get an error message that involves 4, somehow?
Quoting the grammar given for declarations in §7/1 [dcl.dcl]:
static_assert-declaration:
static_assert
( constant-expression , string-literal ) ;
The standard says it has to be a string literal, so you're out of luck; you can't use a constexpr function to construct your error message.
You can, however, use whatever preprocessor magic you like to generate a string literal to go in there. If PI_INT
is a #define instead of a constexpr int
, you could use something like this:
#define PI_INT 4
#define pi_err_str_(x) #x
#define pi_err_str(x) pi_err_str_(x)
#define pi_int_err "PI_INT must be 3, not " pi_err_str(PI_INT)
static_assert(PI_INT == 3, pi_int_err);
output:
error: static assertion failed: "PI_INT must be 3, not 4"
Edit in response to comment by OP and updated question
Is there a way to write a macro that can generalize this so that I can do something like ... and get an error message that involves 4, somehow?
Sure, a bit of preprocessor magic can generalize that, assuming you're happy to be reliant on compiler-specific error message behaviour:
#define strcat_(x, y) x ## y
#define strcat(x, y) strcat_(x, y)
#define PRINT_VALUE(x) template <int> struct strcat(strcat(value_of_, x), _is); static_assert(strcat(strcat(value_of_, x), _is)<x>::x, "");
constexpr int PI_INT = 4;
PRINT_VALUE(PI_INT)
stackoverflow/13465334.cpp:20:1: error: incomplete type ‘value_of_PI_INT_is<4>’ used in nested name specifier
As for other compilers, I don't know what you can do offhand, but you may want to look at a copy of boost's static_assert.hpp to see if any of the tricks employed there can be used to get an evaluated template arg printed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With