Solved Syntax Error with Q_ASSERT
-
@Wieland said in Syntax Error with Q_ASSERT:
The preprocessor is part of the C++ language specification
It is? I've never known that.
Anyways, I got used to C++ coming up with nasty surprises.
Eh, yeah. More syntax means more pitfalls. But tell that to the standards committee ... as you said, just write in Go! ;)
-
The preprocessor only understands
(
and,
in this case (as it's a pre processor i.e. no symbols, namespaces or templates exist at this point), so this is basically parsed asQ_ASSERT(STUFF, OTHER_STUFF);
When you put the extra parentheses it becomesQ_ASSERT(STUFF_IN_PARENTHESES)
.Here's a cute gotcha for the extra parentheses trick:
Because the general rules for type deduction in c++ were pretty boring, c++11 brought such wonders asdecltype
to make it more fun:int foo; bool nudge_nudge_wink_wink = std::is_same<decltype(foo), decltype((foo))>::value; //gives "false"... obviously :P
This marvel is sponsored by the fact that
foo
is an lvalue and(foo)
is an expression ;)So if in your macro you happen to try to deduce the type of the expression passed to it you might have a joyful debugging session.
This is one such super-simplified pattern commonly found in macro based property systems:#define FOO(bar, bazz) decltype(bar) hello = bazz; int foo; FOO(foo, 42); //works fine FOO((foo), 42); //error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
@kshegunov
C++ standard includes C standard by reference. One of the talks at this year's CppCon mentioned that there was a cleanup effort in C++17 made to remove some of the more obscure or irrelevant C headers. -
@Chris-Kawa Thank you for this! Every day a new surprise. Or two.
-
@Chris-Kawa
Yes, I suppose so, I just never thought about it. I don't often think about what the standard does or doesn't include, but I always thought the preprocessor is just a "common non-standardized extension", the language doesn't require it to function. And seeing that code, which I'm happy to say I understand not one iota of, I must reiterate my despise for C++11. :) -
-
C++11 always evokes this feeling in me:
and by the way I'm an atheist ... :] -
I just came up with something that looks like a solution for this to me. What do guys think?
#if !defined(MY_ASSERT) # ifndef QT_NO_DEBUG # define MY_ASSERT_FIRST_ARGUMENT(A, ...) A # define MY_ASSERT(...) ((!MY_ASSERT_FIRST_ARGUMENT(__VA_ARGS__)) ? qt_assert(#__VA_ARGS__,__FILE__,__LINE__) : qt_noop()) # else # define MY_ASSERT(...) qt_noop() # endif #endif
-
@Wieland
where is the docs? ;)
Looks cool. its cryptic enough that it might actually work :) -
@mrjj said in Syntax Error with Q_ASSERT:
Looks cool. its cryptic enough that it might actually work :)
:D :D
-
It's almost the same as the current implementation of Q_ASSERT, just with a variadic macro. So it's C++11 only.
-
@mrjj good one :)
@Wieland Could you explain how it is suppose to work? From what I can decrypt it just checks the first argument passed, so for your original exampleMY_ASSERT(std::is_same<int, int>::value);
it would expand to something like((!std::is_same<int) ? ...
which doesn't make much sense? Or am I missing something?Btw. I get compiler errors for this:
with gcc:in definition of macro MY_ASSERT_FIRST_ARGUMENT wrong number of template arguments (1, should be 2)
with clang:error: expected > MY_ASSERT(std::is_same<int, int>::value);
it compiles in VS2015 U3 although their macro expansion is broken to bits so I wouldn't trust it does what it should. -
@Chris-Kawa Damn, I only tested it with MSVC and it works there :-(
-
@Chris-Kawa My
ideahope was that the preprocessor would be smarter when I confront it with a variadic macro. -
@Wieland I don't think it works. It just compiles ;)
Well you could use something simpler:define MY_ASSERT(...) (!(__VA_ARGS__) ? qt_assert(#__VA_ARGS__,__FILE__,__LINE__) : qt_noop())
and that should be ok, but it has the same drawback I described earlier - it changes the expression it tests by adding extra () around it. Admittedly it's not a big deal and it should work as expected most of the time.
-
@Chris-Kawa Yes it works; funny that it doesn't work for you. Who knows why..
-
@Wieland Maybe I messed up something. http://ideone.com/XKJUnV
-
@Chris-Kawa Ha! Just found out that
#define FIRST(A, ...) A
doesn't work as expected (with MSVC): It doesn't give us the first argument only, instead it just gives all arguments (like__VA_ARGS__
). Maybe I'm wrong here again, but that looks like a bug in MSVC to me and it also explains why the code works.Edit: Maybe it's really a bug in VC's preprocessor, at least someone on SO says so. And the workaround he presents actually seems to fix it, so now my code doesn't compile with MSVC anymore.
-
Thanks everyone for watching me stumbling around like a clown :)
-
@Wieland
Well to be fair, fooling around with Variadic Macros takes more balls than entertaining
clueless children - so it was educational to see that even in 2016, you cannot trust the preprocessor
to work the same across compilers. :)