Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

An assert macro which expands to static_assert when possible?

I have some generic code that needs to run an assertion over the result of a member function. This member function may be constexpr, or it may not be.

template<typename T>
void foo(T t) {
  assert(t.member_function() == 10);
}

Because t.member_function() might be a constant expression, I'm wondering if it's possible to be treated as a static_assert in such cases, but otherwise default to a normal assert. Is this possible?

like image 986
Pubby Avatar asked Nov 02 '22 16:11

Pubby


1 Answers

This is a slightly crazy solution.

Uncomment the Const c; foo(c); line and you'll see that it won't compile. This is the compile-time assert.

It requires variable length arrays, and maybe other compiler specific stuff. I'm on g++-4.6.

The size of the array is either 0 or -1, depending on whether the member function returns 10. So if this can be computed at compile-time, then the compile realizes it's a non-variable length array, and that it has negative size. The negative size allows it to complain. Otherwise, it falls through to a conventional assert.

Please note: I'm getting some core dump with the Runtime version just after the runtime assertion fails. Maybe it doesn't like trying to free an array with negative size. Update: I'm getting core dumps with any assertion failure, even int main() {assert (1==2);}. Is this normal?

#include <iostream>
#include <cassert>
using namespace std;

struct Const {
        constexpr int member_function() { return 9; }
};
struct Runtime {
                  int member_function() { return 9; }
};

template<typename T>
void foo(T t) {
        if(0) {  // so it doesn't actually run any code to malloc/free the vla
            int z[(t.member_function()==10)-1]; // fails at compile-time if necessary
        }
        assert(t.member_function()==10);
}


int main() {
        //Const c; foo(c);
        Runtime r; foo(r);
}
like image 112
Aaron McDaid Avatar answered Nov 11 '22 09:11

Aaron McDaid