I have the following macros for certain compile-time checks:
/* in-expression compile-time check evaluating to 0 */
#ifdef __cplusplus
template<bool> struct Chk_sa;
template<> struct Chk_sa<true>{};
#define Chk(test) (sizeof((Chk_sa<!!(0+(test))>())) * 0)
#else
#define Chk(test) (sizeof(struct { int (Chk):((0+(test)) ? 1 : -1); }) * 0)
#endif
/* ensure value x is a constant expression */
#ifdef __cplusplus
template<bool,bool> struct CEx_sa;
template<> struct CEx_sa<true,false>{};
template<> struct CEx_sa<false,true>{};
#define CEx(x) (sizeof((CEx_sa<!!(0+(x)), !(0+(x))>())) * 0 + (x))
#else
#define CEx(x) (sizeof(struct { int (CEx):(((0+(x)) && 1) + 1); }) * 0 + (x))
#endif
/* usage like this: */
struct ChkTest {
int expr1[Chk(3*3) + 1]; // supposed to be [1]
int expr2 : CEx(3*3); // supposed to be : 9
};
However, the C++ part of this fails with a parse error already for uses of the Chk
macro, at the )
before the * 0
part. (I included the CEx
part for completeness, as I’ll need both fixed.)
How can I change these to work with older G++ (GCC) versions? Specifically, these work on Debian etch (G++ 4.1.1) and fail on Debian sargs (G++ 3.3.5) and older.
(Note: I’m a C programmer but don’t really know C++.)
Update: the precise error message was requested. I saved the snippet above into a file x
:
$ gcc -x c -c x
$ gcc -x c++ -c x
x:22: error: parse error before `)' token
x:23: error: parse error before `)' token
Update: this is notably not an is_constexpr
but a compile-time check to ensure that the expression is compile-time constant which in itself is usable inside a constant expression and aborts compilation if it’s not a compile-time constant.
I managed to figure it out:
template<bool> struct mbccChkExpr_sa;
-template<> struct mbccChkExpr_sa<true>{};
-#define mbccChkExpr(test) (sizeof((mbccChkExpr_sa<!!(0+(test))>())) * 0)
+template<> struct mbccChkExpr_sa<true> { typedef int Type; };
+#define mbccChkExpr(test) (static_cast<mbccChkExpr_sa<!!(0+(test))>::Type>(0))
and:
template<bool,bool> struct mbccCEX_sa;
-template<> struct mbccCEX_sa<true,false>{};
-template<> struct mbccCEX_sa<false,true>{};
-#define mbccCEX(x) (sizeof((mbccCEX_sa<!!(0+(x)), !(0+(x))>())) * 0 + (x))
+template<> struct mbccCEX_sa<true,false> { typedef int Type; };
+template<> struct mbccCEX_sa<false,true> { typedef int Type; };
+#define mbccCEX(x) (static_cast<mbccCEX_sa<!!(0+(x)), !(0+(x))>::Type>(0) + (x))
I still wonder if I can somehow put the type of x
into the latter so I can do static_cast<…>(x)
instead of static_cast<…>(0) + (x)
but this already works, also on OpenWatcom and sarge’s g++
.