How do I reliably static_assert on anything that isn't a string literal?
For example, in the following code, I've attempted to wrap the standard assert macro but statically reject anything for the message that's not a string literal (since anything but a string literal will not be displayed at runtime when the assert triggers).
#include <cassert>
#include <string>
#include <type_traits>
#define my_assert(test, message)\
static_assert(\
(\
!std::is_pointer<decltype(message)>::value &&\
!std::is_array<decltype(message)>::value\
),\
"literal string required"\
);\
assert((message, (test)));
int main() {
my_assert(1 == 1, "one equals one");
my_assert(1 == 2, "one equals two");
{
const char *msg = "one equals one";
//my_assert(1 == 1, msg); // triggers static_assert
}
{
const char msg[] = "one equals one";
//my_assert(1 == 1, msg); // triggers static_assert
}
{
const std::string msg = "one equals one";
//my_assert(1 == 1, msg.c_str()); // triggers static_assert
}
{
const int msg = 3;
my_assert(1 == 1, msg); // should trigger static_assert
}
}
As you can see, the testing is done via the tests provided by the type_traits header, and, mostly, this code works as intended (tested with gcc 4.7.2). However, it doesn't specifically look for string literals as much as it just rejects common things that a programmer might use in place.
The solution I have may be good enough for the example above, but I'd like to use this, or a similar technique in other situations as well.
So the question is, how do I reliably use type_traits (or another standard mechanism) to static_assert on anything except a string literal?
A "string literal" is a sequence of characters from the source character set enclosed in double quotation marks (" "). String literals are used to represent a sequence of characters which, taken together, form a null-terminated string. You must always prefix wide-string literals with the letter L.
yes it is perfectly safe and considered standard practice. String literals are guaranteed to be properly null terminated.
However, string literal types currently can't be used as index signature parameter types.
This means that a string literal is written as: a quote, followed by zero, one, or more non-quote characters, followed by a quote. In practice this is often complicated by escaping, other delimiters, and excluding newlines.
Here is the best I could get, which appears to reject anything I throw at it, but still accepts literal strings:
#define my_assert(test, message)\
static_assert(\
(\
std::is_convertible <decltype(message), const char *>::value &&\
!std::is_rvalue_reference <decltype(message)>::value &&\
!std::is_pointer <decltype(message)>::value &&\
!std::is_array <decltype(message)>::value &&\
!std::is_class <decltype(message)>::value\
),\
"string literal required"\
);\
assert((message, (test)))
I'd be very interested to know if this actually is exhaustively correct, and/or if there is a simpler way to do this detection.
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