(this question was inspired by How can I generate a compilation error to prevent certain VALUE (not type) to go into the function?)
Let\'s say, we have a single-argument
It's not perfect and it requires us to use arguments in two different places, but it 'works':
template<int N = 0>
int foo(int arg = 0) {
static_assert(N != 5, "N cannot be 5!");
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
We can call it like so:
foo<5>(); // does not compile
foo(5); // UB
foo<5>(5); // does not compile
foo<5>(10); // does not compile
foo<10>(5); // UB
foo(); // fine
foo<10>(); // fine
foo(10); // fine
gcc/clang/intel compilers support __builtin_constant_p, so you can use something like that:
template <int D>
int foo_ub(int arg) {
static_assert(D != 5, "error");
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
#define foo(e) foo_ub< __builtin_constant_p(e) ? e : 0 >(e)
these statements produce compile time error:
foo(5)
foo(2+3)
constexpr int i = 5; foo(i);
while all others - runtime segfault (or ub if no nullptr
is used)
I got error with constexpr
when used in constant expression for:
constexpr int foo(int arg) {
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
Demo
We cannot know that argument value is known at compile type, but we can use type representing value with std::integral_constant
// alias to shorten name.
template <int N>
using int_c = std::integral_constant<int, N>;
Possibly with UDL with operator "" _c
to have 5_c
, 42_c
.
and then, add overload with that:
template <int N>
constexpr auto foo(int_c<N>) {
return int_c<foo(N)>{};
}
So:
foo(int_c<42>{}); // OK
foo(int_c<5>{}); // Fail to compile
// and with previous constexpr:
foo(5); // Runtime error, No compile time diagnostic
constexpr auto r = foo(5); // Fail to compile
As I said, arguments are not known to be constant inside the function, and is_constexpr seems not possible in standard to allow dispatch, but some compiler provide built-in for that (__builtin_constant_p
), so with MACRO, we can do the dispatch:
#define FOO(X) [&](){ \
if constexpr (__builtin_constant_p(X)) {\
return foo(int_c<__builtin_constant_p (X) ? X : 0>{});\
} else {\
return foo(X); \
} \
}()
Demo
Note: Cannot use foo(int_c<X>{})
directly, even in if constexpr, as there is still some syntax check.