问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/13465334/stdcout-equivalent-at-compile-time-or-static-assert-stringification-of-compil