Ответ 1
Типичный способ сделать это в C с помощью компилятора gcc, который также будет работать в C++: вы используете встроенный __builtin_constant_p
для проверки, является ли выражение постоянно вычисляемым, затем проверяете выражение и затем вызываете функцию, объявленную с помощью __attribute__((__warning__))
или с помощью __attribute__((__error__))
. Вот так:
#include <cassert>
#include <type_traits>
#define CONCAT(a, b) a ## b
#define XCONCAT(a, b) CONCAT(a, b)
#define maybe_static_maybe_not_assert(expr) do { \
if (__builtin_constant_p(expr)) { \
if (!(expr)) { \
extern __attribute__((__warning__( \
"static_assert: expression: " #expr " will fail on runtime!" \
))) void XCONCAT(maybe_static_maybe_not_assert_warn, __LINE__)(); \
XCONCAT(maybe_static_maybe_not_assert_warn, __LINE__)(); \
} \
} \
assert(expr); \
} while(0)
struct Dimensions {
Dimensions& operator=(int i) {
maybe_static_maybe_not_assert(i != 0);
return *this;
}
};
int getDim();
int main() {
Dimensions dims;
dims = getDim();
dims = 0;
dims = 1;
return 0;
}
При компиляции с оптимизацией должно выдаваться предупреждение:
In member function 'Dimensions& Dimensions::operator=(int)',
inlined from 'int main()' at <source>:32:12:
<source>:12:70: warning: call to 'maybe_static_maybe_not_assert_warn21' declared with attribute warning: static_assert: expression: i != 0 will fail on runtime! [-Wattribute-warning]
12 | XCONCAT(maybe_static_maybe_not_assert_warn, __LINE__)(); \
| ^
<source>:21:9: note: in expansion of macro 'maybe_static_maybe_not_assert'
21 | maybe_static_maybe_not_assert(i != 0);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compiler returned: 0
Именно так _FORTIFY_SOURCE
реализован в glibc.