I'm looking for a way to simulate certain overloaded GCC built-ins in C++. The built-ins are similar to these:
__builtin_foo(char *a, signed int b); __builtin_foo(short *a, signed int b); __builtin_foo(long *a, signed int b);
With a special limitation hard coded in GCC: b
must be a literal value, i.e. you can call:
__builtin_foo((char *)0, 1);
but not:
extern int val; __builtin_foo((char *)0, val);
which generates a compiler error. I've fiddled with std::enable_if
to simulate this but cannot find a way to enforce that only literal arguments are accepted. Is there a way to do this?
Integer literals are numbers that do not have a decimal point or an exponential part. They can be represented as: Decimal integer literals. Hexadecimal integer literals.
In computer science, an integer literal is a kind of literal for an integer whose value is directly represented in source code.
Here is a portable C++11 solution so that your function (macro actually, sorry) accepts only integer literals and triggers a compile-time error instead:
constexpr int operator "" _literal(unsigned long long i) { return i; } #define m_builtin_foo(integer) builtin_foo(integer ## _literal)
User-defined literals accept only literals (hence their name). Therefore, if you make your macro paste a user-defined literal to what is passed to it, it should only accept the literals accepted by the corresponding user-defined literal.
However, that's rather ugly and I guess that could be error-prone. Not sure how though.
@MichaelAnderson pointed in the comments that m_builtin_foo(i+1)
would still work. That's right. @Angew suggested wrapping the return type of _literal
in a wrapper incompatible with integer arithmetic and adding explicit conversions. He was also right, here is the more complete solution:
struct wrapper { constexpr wrapper(int n): value{n} {} explicit constexpr operator int() const { return value; } int value; }; constexpr wrapper operator "" _literal(unsigned long long i) { return { int(i) }; } #define m_builtin_foo(integer) builtin_foo(int(integer ## _literal))
You can sort of simulate it using a macro and the GCC intrinsic __builtin_constant_p
constexpr int foo(int i) { return i; } #define FOO(i) do { \ static_assert(__builtin_constant_p(i), "Not a constant"); \ foo(i); \ } while (false)
This will allow FOO(1)
to compile, but not int i = 1; FOO(i);
However, the result of __builtin_constant_p
depends on the optimisation level, at higher levels of optimisation const
variables are treated as constants, so it doesn't only accept literals.
Of course if you're willing to allow constant-expressions, not just literals, then all you have to do is use the variable in a context that requires a constant-expression, such as a static assertion or a non-type template argument.
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