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
Forum Updated to NodeBB v4.3 + New Features

Syntax Error with Q_ASSERT

Scheduled Pinned Locked Moved Solved C++ Gurus
25 Posts 5 Posters 11.5k 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.
  • 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