Reputation:
I want to implement my_static_assert
that slightly differs from c++17 single-parametric static_assert
: if condition inside my_static_assert
is not known at compile time, it should pass.
The second my_static_assert
in the following example should pass but if I would use static_assert
it will fail.
#include <iostream>
int x, y;
constexpr int f1() { return 0; }
constexpr int f2() { return 0; }
int f3() { return x; }
int f4() { return y; }
constexpr int sum(int a, int b) { return a + b; }
int main() {
std::cin >> x >> y;
// it should fail
my_static_assert(sum(sum(f1(), f2()), sum(f1(), f1())) != 0);
// it should pass
my_static_assert(sum(sum(f1(), f2()), sum(f4(), sum(f3(), f1()))) != 0);
}
If you want to know why this question arised:
I am building expressions using leaf functions f1,f2,f3,f4 and operations on the expression nodes: sum,mul,div,sub. Leafs that are known at compile time contain value that is always 0.
I am trying to check that my expressions contain at least one element that is not known at compile time.
Upvotes: 11
Views: 251
Reputation: 170074
If you are willing to commit to a compiler with GNU extensions, it's possible. So be warned.
It takes two overloads and a helper macro:
template<std::size_t N>
constexpr void assert_helpr(int(&)[N]) = delete;
void assert_helpr(...) {}
#define my_static_assert(...) do { \
__extension__ int _tmp [(__VA_ARGS__) + 1]; \
assert_helpr(_tmp); \
} while(0)
It works as follows:
I haven't tested it thoroughly, but it seems to work on both Clang and GCC. See it live.
@Artyer was kind enough to share a solution based on this approach on godbolt.
Here's a reduction of that code to this problem:
template<std::size_t N>
constexpr std::false_type assert_helpr(int(&)[N]);
constexpr std::true_type assert_helpr(...);
#define my_static_assert(...) do { \
__extension__ int _tmp[(__VA_ARGS__) + 1]; \
static_assert(decltype(assert_helpr(_tmp)){}, #__VA_ARGS__); \
} while(0)
Same use of overloading, except this time we grab an actual result type from the call via decltype
, and proceed to create a true compile time Boolean constant out of it.
This allows direct use of static_assert
, and as a nice to have feature, we can pass it the stringified token soup to get an indication in the error of the expression that failed.
Upvotes: 7