Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. Syntax Error with Q_ASSERT
Qt 6.11 is out! See what's new in the release blog

Syntax Error with Q_ASSERT

Scheduled Pinned Locked Moved Solved C++ Gurus
25 Posts 5 Posters 19.1k Views 5 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • ? A Former User

    @kshegunov The preprocessor is part of the C++ language specification and I would expect that, besides all the other smart things it also can do, it is able to handle such situations in a sane way. Anyways, I got used to C++ coming up with nasty surprises.

    Edit: Next time maybe better Write in Go ;-)

    kshegunovK Offline
    kshegunovK Offline
    kshegunov
    Moderators
    wrote on last edited by
    #7

    @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! ;)

    Read and abide by the Qt Code of Conduct

    1 Reply Last reply
    1
    • Chris KawaC Offline
      Chris KawaC Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on last edited by
      #8

      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 as Q_ASSERT(STUFF, OTHER_STUFF); When you put the extra parentheses it becomes Q_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 as decltype 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.

      ? kshegunovK 2 Replies Last reply
      5
      • Chris KawaC Chris Kawa

        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 as Q_ASSERT(STUFF, OTHER_STUFF); When you put the extra parentheses it becomes Q_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 as decltype 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.

        ? Offline
        ? Offline
        A Former User
        wrote on last edited by
        #9

        @Chris-Kawa Thank you for this! Every day a new surprise. Or two.

        1 Reply Last reply
        1
        • Chris KawaC Chris Kawa

          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 as Q_ASSERT(STUFF, OTHER_STUFF); When you put the extra parentheses it becomes Q_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 as decltype 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.

          kshegunovK Offline
          kshegunovK Offline
          kshegunov
          Moderators
          wrote on last edited by
          #10

          @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. :)

          Read and abide by the Qt Code of Conduct

          1 Reply Last reply
          1
          • Chris KawaC Offline
            Chris KawaC Offline
            Chris Kawa
            Lifetime Qt Champion
            wrote on last edited by
            #11

            @kshegunov

            I must reiterate my despise for C++11. :)

            There there... <pat on the back> :)

            kshegunovK 1 Reply Last reply
            3
            • Chris KawaC Chris Kawa

              @kshegunov

              I must reiterate my despise for C++11. :)

              There there... <pat on the back> :)

              kshegunovK Offline
              kshegunovK Offline
              kshegunov
              Moderators
              wrote on last edited by kshegunov
              #12

              C++11 always evokes this feeling in me:

              and by the way I'm an atheist ... :]

              Read and abide by the Qt Code of Conduct

              1 Reply Last reply
              2
              • ? Offline
                ? Offline
                A Former User
                wrote on last edited by
                #13

                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
                
                mrjjM 1 Reply Last reply
                0
                • ? A Former User

                  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
                  
                  mrjjM Offline
                  mrjjM Offline
                  mrjj
                  Lifetime Qt Champion
                  wrote on last edited by
                  #14

                  @Wieland
                  where is the docs? ;)
                  Looks cool. its cryptic enough that it might actually work :)

                  K 1 Reply Last reply
                  0
                  • mrjjM mrjj

                    @Wieland
                    where is the docs? ;)
                    Looks cool. its cryptic enough that it might actually work :)

                    K Offline
                    K Offline
                    koahnig
                    wrote on last edited by
                    #15

                    @mrjj said in Syntax Error with Q_ASSERT:

                    Looks cool. its cryptic enough that it might actually work :)

                    :D :D

                    Vote the answer(s) that helped you to solve your issue(s)

                    1 Reply Last reply
                    1
                    • ? Offline
                      ? Offline
                      A Former User
                      wrote on last edited by A Former User
                      #16

                      It's almost the same as the current implementation of Q_ASSERT, just with a variadic macro. So it's C++11 only.

                      1 Reply Last reply
                      0
                      • Chris KawaC Offline
                        Chris KawaC Offline
                        Chris Kawa
                        Lifetime Qt Champion
                        wrote on last edited by Chris Kawa
                        #17

                        @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.

                        ? 2 Replies Last reply
                        1
                        • Chris KawaC Chris Kawa

                          @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.

                          ? Offline
                          ? Offline
                          A Former User
                          wrote on last edited by
                          #18

                          @Chris-Kawa Damn, I only tested it with MSVC and it works there :-(

                          1 Reply Last reply
                          1
                          • Chris KawaC Chris Kawa

                            @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.

                            ? Offline
                            ? Offline
                            A Former User
                            wrote on last edited by A Former User
                            #19

                            @Chris-Kawa My idea hope was that the preprocessor would be smarter when I confront it with a variadic macro.

                            1 Reply Last reply
                            0
                            • Chris KawaC Offline
                              Chris KawaC Offline
                              Chris Kawa
                              Lifetime Qt Champion
                              wrote on last edited by
                              #20

                              @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.

                              ? 1 Reply Last reply
                              0
                              • Chris KawaC Chris Kawa

                                @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.

                                ? Offline
                                ? Offline
                                A Former User
                                wrote on last edited by A Former User
                                #21

                                @Chris-Kawa Yes it works; funny that it doesn't work for you. Who knows why..

                                1 Reply Last reply
                                0
                                • Chris KawaC Offline
                                  Chris KawaC Offline
                                  Chris Kawa
                                  Lifetime Qt Champion
                                  wrote on last edited by
                                  #22

                                  @Wieland Maybe I messed up something. http://ideone.com/XKJUnV

                                  ? 1 Reply Last reply
                                  0
                                  • Chris KawaC Chris Kawa

                                    @Wieland Maybe I messed up something. http://ideone.com/XKJUnV

                                    ? Offline
                                    ? Offline
                                    A Former User
                                    wrote on last edited by A Former User
                                    #23

                                    @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.

                                    1 Reply Last reply
                                    1
                                    • ? Offline
                                      ? Offline
                                      A Former User
                                      wrote on last edited by
                                      #24

                                      Thanks everyone for watching me stumbling around like a clown :)

                                      mrjjM 1 Reply Last reply
                                      2
                                      • ? A Former User

                                        Thanks everyone for watching me stumbling around like a clown :)

                                        mrjjM Offline
                                        mrjjM Offline
                                        mrjj
                                        Lifetime Qt Champion
                                        wrote on last edited by
                                        #25

                                        @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. :)

                                        1 Reply Last reply
                                        1

                                        • Login

                                        • Login or register to search.
                                        • First post
                                          Last post
                                        0
                                        • Categories
                                        • Recent
                                        • Tags
                                        • Popular
                                        • Users
                                        • Groups
                                        • Search
                                        • Get Qt Extensions
                                        • Unsolved