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. Unnecessary const referencing
Qt 6.11 is out! See what's new in the release blog

Unnecessary const referencing

Scheduled Pinned Locked Moved Solved C++ Gurus
18 Posts 7 Posters 3.0k 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.
  • JonBJ Online
    JonBJ Online
    JonB
    wrote on last edited by JonB
    #1

    Over in https://forum.qt.io/topic/146160/unresolved-external-symbol-error OP declared:

    template<typename T>
    bool Numbers::isPerfectPower(const T& number, const int &n)
    

    and then proceeds to instantiate it with T as e.g. double.

    On the basis of the C++ mantra of "why write 1 token when you can write 3", is it now the C++ "thing" that we pass numbers as const type & when we could write plain type? I would have written

    template<typename T>
    bool Numbers::isPerfectPower(T number, int n)
    

    For the T unless it's some "complex numeric type", such as perhaps an imaginary or unlimited precision number, why should I prefer const T & over T here? And certainly as for the second argument, why const int & over int?

    Is this just the modern C++ style? Is there some reason why it's more suitable here perhaps in a template? In general do you pass ints as const int &? Or do people just like typing a lot?

    J.HilkJ sierdzioS Chris KawaC 3 Replies Last reply
    0
    • JonBJ JonB

      Over in https://forum.qt.io/topic/146160/unresolved-external-symbol-error OP declared:

      template<typename T>
      bool Numbers::isPerfectPower(const T& number, const int &n)
      

      and then proceeds to instantiate it with T as e.g. double.

      On the basis of the C++ mantra of "why write 1 token when you can write 3", is it now the C++ "thing" that we pass numbers as const type & when we could write plain type? I would have written

      template<typename T>
      bool Numbers::isPerfectPower(T number, int n)
      

      For the T unless it's some "complex numeric type", such as perhaps an imaginary or unlimited precision number, why should I prefer const T & over T here? And certainly as for the second argument, why const int & over int?

      Is this just the modern C++ style? Is there some reason why it's more suitable here perhaps in a template? In general do you pass ints as const int &? Or do people just like typing a lot?

      J.HilkJ Offline
      J.HilkJ Offline
      J.Hilk
      Moderators
      wrote on last edited by
      #2

      @JonB there is no reason to pass an int as const ref, it is in fact more work and memory intensive than simply copying it over.

      Maybe if you're working on a microcontroller that works with 2 byte pointers and you're passing an int64 around, maybe.

      if your template parameter is supposed to be only an interagier of some kind I would remove the const ref and make an static assert type check.

      If your function also accepts complex types, than yes, const ref it.

      IMHO


      Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


      Q: What's that?
      A: It's blue light.
      Q: What does it do?
      A: It turns blue.

      1 Reply Last reply
      2
      • JonBJ JonB

        Over in https://forum.qt.io/topic/146160/unresolved-external-symbol-error OP declared:

        template<typename T>
        bool Numbers::isPerfectPower(const T& number, const int &n)
        

        and then proceeds to instantiate it with T as e.g. double.

        On the basis of the C++ mantra of "why write 1 token when you can write 3", is it now the C++ "thing" that we pass numbers as const type & when we could write plain type? I would have written

        template<typename T>
        bool Numbers::isPerfectPower(T number, int n)
        

        For the T unless it's some "complex numeric type", such as perhaps an imaginary or unlimited precision number, why should I prefer const T & over T here? And certainly as for the second argument, why const int & over int?

        Is this just the modern C++ style? Is there some reason why it's more suitable here perhaps in a template? In general do you pass ints as const int &? Or do people just like typing a lot?

        sierdzioS Offline
        sierdzioS Offline
        sierdzio
        Moderators
        wrote on last edited by
        #3

        @JonB For POD types, passing a copy (int number, int n) is enough. A const reference in such case is needlessly complicating stuff for no gain at all.

        What I often do for POD types, however, is to pass them as const without a reference (const number, const int n). This offers no advantage in terms of performance but makes it kind of clear that these are input parameters and that they will not change.

        (Z(:^

        jsulmJ J.HilkJ 2 Replies Last reply
        3
        • JonBJ Online
          JonBJ Online
          JonB
          wrote on last edited by
          #4

          @J-Hilk , @sierdzio
          Thanks, so far your replies have attuned with what I would do. It's good to know there does not seem to be a special reason/style for this const & here.

          1 Reply Last reply
          0
          • sierdzioS sierdzio

            @JonB For POD types, passing a copy (int number, int n) is enough. A const reference in such case is needlessly complicating stuff for no gain at all.

            What I often do for POD types, however, is to pass them as const without a reference (const number, const int n). This offers no advantage in terms of performance but makes it kind of clear that these are input parameters and that they will not change.

            jsulmJ Offline
            jsulmJ Offline
            jsulm
            Lifetime Qt Champion
            wrote on last edited by
            #5

            @sierdzio said in Unnecessary const referencing:

            makes it kind of clear that these are input parameters and that they will not change

            Also, this way, you make sure they are not changed by accident.

            https://forum.qt.io/topic/113070/qt-code-of-conduct

            1 Reply Last reply
            0
            • sierdzioS sierdzio

              @JonB For POD types, passing a copy (int number, int n) is enough. A const reference in such case is needlessly complicating stuff for no gain at all.

              What I often do for POD types, however, is to pass them as const without a reference (const number, const int n). This offers no advantage in terms of performance but makes it kind of clear that these are input parameters and that they will not change.

              J.HilkJ Offline
              J.HilkJ Offline
              J.Hilk
              Moderators
              wrote on last edited by
              #6

              @sierdzio said in Unnecessary const referencing:

              What I often do for POD types, however, is to pass them as const without a reference (const number, const int n). This offers no advantage in terms of performance but makes it kind of clear that these are input parameters and that they will not change.

              I actually like to do that too, but some code models / compilers actually give you a warning about this

              So I usually end up with the declaration of

              void constArgument(int someArgument);
              

              and a definition of

              void SomeClass::constArgument(const int someArgument)
              {
                  qDebug() << someArgument;
              }
              

              Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


              Q: What's that?
              A: It's blue light.
              Q: What does it do?
              A: It turns blue.

              JonBJ 1 Reply Last reply
              0
              • J.HilkJ J.Hilk

                @sierdzio said in Unnecessary const referencing:

                What I often do for POD types, however, is to pass them as const without a reference (const number, const int n). This offers no advantage in terms of performance but makes it kind of clear that these are input parameters and that they will not change.

                I actually like to do that too, but some code models / compilers actually give you a warning about this

                So I usually end up with the declaration of

                void constArgument(int someArgument);
                

                and a definition of

                void SomeClass::constArgument(const int someArgument)
                {
                    qDebug() << someArgument;
                }
                
                JonBJ Online
                JonBJ Online
                JonB
                wrote on last edited by
                #7

                @J-Hilk
                And why C++ allows you to have a different definition from declaration for this case is beyond me....

                J.HilkJ 1 Reply Last reply
                1
                • JonBJ JonB

                  @J-Hilk
                  And why C++ allows you to have a different definition from declaration for this case is beyond me....

                  J.HilkJ Offline
                  J.HilkJ Offline
                  J.Hilk
                  Moderators
                  wrote on last edited by
                  #8

                  @JonB This is allowed because const is purely an implementation detail when passing by value


                  Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                  Q: What's that?
                  A: It's blue light.
                  Q: What does it do?
                  A: It turns blue.

                  1 Reply Last reply
                  0
                  • JonBJ JonB has marked this topic as solved on
                  • JonBJ JonB

                    Over in https://forum.qt.io/topic/146160/unresolved-external-symbol-error OP declared:

                    template<typename T>
                    bool Numbers::isPerfectPower(const T& number, const int &n)
                    

                    and then proceeds to instantiate it with T as e.g. double.

                    On the basis of the C++ mantra of "why write 1 token when you can write 3", is it now the C++ "thing" that we pass numbers as const type & when we could write plain type? I would have written

                    template<typename T>
                    bool Numbers::isPerfectPower(T number, int n)
                    

                    For the T unless it's some "complex numeric type", such as perhaps an imaginary or unlimited precision number, why should I prefer const T & over T here? And certainly as for the second argument, why const int & over int?

                    Is this just the modern C++ style? Is there some reason why it's more suitable here perhaps in a template? In general do you pass ints as const int &? Or do people just like typing a lot?

                    Chris KawaC Offline
                    Chris KawaC Offline
                    Chris Kawa
                    Lifetime Qt Champion
                    wrote on last edited by
                    #9

                    There's nothing "technically" wrong here. The problem here is bad API design. On one hand it tries to be generic, so it doesn't restrict the type and uses const& for cases where you pass some "big" type that benefits from passing by reference. On the other it pessimizes the actually intended use case, which are the basic numeric types. So basically it's the worst of both worlds. It's optimized for case it won't be used for.
                    A good API design would first analyze use cases. If it's just for the basic types you can restrict the allowed types with something like std::is_arithmetic or a concept and pass by value. If it's for any type, but you don't want to loose on performance for any case then provide an overload for the two ways.

                    Christian EhrlicherC 1 Reply Last reply
                    3
                    • Chris KawaC Chris Kawa

                      There's nothing "technically" wrong here. The problem here is bad API design. On one hand it tries to be generic, so it doesn't restrict the type and uses const& for cases where you pass some "big" type that benefits from passing by reference. On the other it pessimizes the actually intended use case, which are the basic numeric types. So basically it's the worst of both worlds. It's optimized for case it won't be used for.
                      A good API design would first analyze use cases. If it's just for the basic types you can restrict the allowed types with something like std::is_arithmetic or a concept and pass by value. If it's for any type, but you don't want to loose on performance for any case then provide an overload for the two ways.

                      Christian EhrlicherC Offline
                      Christian EhrlicherC Offline
                      Christian Ehrlicher
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      What's wrong with

                      template <typename T>
                      bool Numbers::isPerfectPower(T &&number, int n);
                      

                      :)

                      https://godbolt.org/z/afW38b9e8

                      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                      Visit the Qt Academy at https://academy.qt.io/catalog

                      Chris KawaC 1 Reply Last reply
                      1
                      • Christian EhrlicherC Christian Ehrlicher

                        What's wrong with

                        template <typename T>
                        bool Numbers::isPerfectPower(T &&number, int n);
                        

                        :)

                        https://godbolt.org/z/afW38b9e8

                        Chris KawaC Offline
                        Chris KawaC Offline
                        Chris Kawa
                        Lifetime Qt Champion
                        wrote on last edited by
                        #11

                        @Christian-Ehrlicher said:

                        What's wrong with

                        This:
                        https://godbolt.org/z/bxcs7b355

                        kshegunovK 1 Reply Last reply
                        1
                        • JonBJ Online
                          JonBJ Online
                          JonB
                          wrote on last edited by
                          #12

                          God I love this --- an assembly language debate! :D

                          J.HilkJ 1 Reply Last reply
                          0
                          • JonBJ JonB

                            God I love this --- an assembly language debate! :D

                            J.HilkJ Offline
                            J.HilkJ Offline
                            J.Hilk
                            Moderators
                            wrote on last edited by
                            #13

                            @JonB said in Unnecessary const referencing:

                            God I love this --- an assembly language debate! :D

                            alt text


                            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                            Q: What's that?
                            A: It's blue light.
                            Q: What does it do?
                            A: It turns blue.

                            1 Reply Last reply
                            0
                            • Chris KawaC Chris Kawa

                              @Christian-Ehrlicher said:

                              What's wrong with

                              This:
                              https://godbolt.org/z/bxcs7b355

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

                              @Chris-Kawa said in Unnecessary const referencing:

                              @Christian-Ehrlicher said:

                              What's wrong with

                              This:
                              https://godbolt.org/z/bxcs7b355

                              Of course one would do something like this, instead:

                              template <typename T>
                              std::remove_reference_t<T> foo1(T&& a) { return std::forward<T>(a) + 42; }
                              

                              https://godbolt.org/z/8nT5verW4

                              Granted, it still misses the opportunity to use lea instead of resolving the address through mov but works with whatever you pass it. I'd argue that for numeric/primitive types the compiler should expand a const lvalue to a copy at the optimizer pass, but it apparently doesn't.

                              Read and abide by the Qt Code of Conduct

                              JonBJ Chris KawaC 2 Replies Last reply
                              0
                              • kshegunovK kshegunov

                                @Chris-Kawa said in Unnecessary const referencing:

                                @Christian-Ehrlicher said:

                                What's wrong with

                                This:
                                https://godbolt.org/z/bxcs7b355

                                Of course one would do something like this, instead:

                                template <typename T>
                                std::remove_reference_t<T> foo1(T&& a) { return std::forward<T>(a) + 42; }
                                

                                https://godbolt.org/z/8nT5verW4

                                Granted, it still misses the opportunity to use lea instead of resolving the address through mov but works with whatever you pass it. I'd argue that for numeric/primitive types the compiler should expand a const lvalue to a copy at the optimizer pass, but it apparently doesn't.

                                JonBJ Online
                                JonBJ Online
                                JonB
                                wrote on last edited by JonB
                                #15

                                @kshegunov
                                Why write this getting-more-complex-all-the-time code if you can instead write:

                                template <typename T>
                                bool Numbers::isPerfectPower(T number, int n);
                                

                                (given usage for POD numerics)? I just don't get how having to know about and add in

                                std::remove_reference_t<T>
                                std::forward<T>
                                

                                is anything other than making C++ harder. I like C++, but what you're asking me, the programmer, to remember is getting out of hand.....

                                Chris KawaC 1 Reply Last reply
                                0
                                • JonBJ JonB

                                  @kshegunov
                                  Why write this getting-more-complex-all-the-time code if you can instead write:

                                  template <typename T>
                                  bool Numbers::isPerfectPower(T number, int n);
                                  

                                  (given usage for POD numerics)? I just don't get how having to know about and add in

                                  std::remove_reference_t<T>
                                  std::forward<T>
                                  

                                  is anything other than making C++ harder. I like C++, but what you're asking me, the programmer, to remember is getting out of hand.....

                                  Chris KawaC Offline
                                  Chris KawaC Offline
                                  Chris Kawa
                                  Lifetime Qt Champion
                                  wrote on last edited by Chris Kawa
                                  #16

                                  @JonB said:

                                  Why write this getting-more-complex-all-the-time code if you can instead write

                                  Because nothing in that syntax prevents you from passing e.g. a BigNum class instance, that would be heavily penalized for using a by value parameter (copy).

                                  That's why I mentioned restricting possible inputs e.g.

                                  template<typename T>
                                  concept ByValueType = std::is_arithmetic_v<T>;
                                  
                                  template <ByValueType T>
                                  bool Numbers::isPerfectPower(T number, int n);
                                  

                                  or whatever other condition you think is appropriate, like checking the sizeof of the type to see if it fits in a register or using some custom type traits to separate types that should be passed by value from those that benefit from referencing.

                                  Of course all of this discussion is academic given how wasteful the actual implementation of the OPs function is. Any benefits we come up on the parameter front are immediately buried just few lines into the function body, but hey, why not :)

                                  1 Reply Last reply
                                  1
                                  • kshegunovK kshegunov

                                    @Chris-Kawa said in Unnecessary const referencing:

                                    @Christian-Ehrlicher said:

                                    What's wrong with

                                    This:
                                    https://godbolt.org/z/bxcs7b355

                                    Of course one would do something like this, instead:

                                    template <typename T>
                                    std::remove_reference_t<T> foo1(T&& a) { return std::forward<T>(a) + 42; }
                                    

                                    https://godbolt.org/z/8nT5verW4

                                    Granted, it still misses the opportunity to use lea instead of resolving the address through mov but works with whatever you pass it. I'd argue that for numeric/primitive types the compiler should expand a const lvalue to a copy at the optimizer pass, but it apparently doesn't.

                                    Chris KawaC Offline
                                    Chris KawaC Offline
                                    Chris Kawa
                                    Lifetime Qt Champion
                                    wrote on last edited by Chris Kawa
                                    #17

                                    @kshegunov Sure, but that's kinda another topic. What you show is just the intended benefit of small perfectly forwarded functions i.e. they completely disappear via inlining. That wouldn't happen though in a longer function, like what the OP has, so the benefit you show is indeed valid, but not really related to the topic at hand. Notice that you're actually doing what I proposed i.e. have an overload for copy and ref variants. The inlined && forward is just an unrelated complication for style points.

                                    Btw. I love how the float version transforms into a fixed point xmm arithmetic with magic constant. Compilers are so smart these days :)

                                    kshegunovK 1 Reply Last reply
                                    0
                                    • Chris KawaC Chris Kawa

                                      @kshegunov Sure, but that's kinda another topic. What you show is just the intended benefit of small perfectly forwarded functions i.e. they completely disappear via inlining. That wouldn't happen though in a longer function, like what the OP has, so the benefit you show is indeed valid, but not really related to the topic at hand. Notice that you're actually doing what I proposed i.e. have an overload for copy and ref variants. The inlined && forward is just an unrelated complication for style points.

                                      Btw. I love how the float version transforms into a fixed point xmm arithmetic with magic constant. Compilers are so smart these days :)

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

                                      @Chris-Kawa said in Unnecessary const referencing:

                                      Notice that you're actually doing what I proposed i.e. have an overload for copy and ref variants.

                                      No argument there.

                                      The inlined && forward is just an unrelated complication for style points.

                                      As far as we are talking + 42, if for example the body was something like:

                                      template <typename T>
                                      std::remove_reference_t<T> foo1(T&& a) {
                                          return smthng(std::forward<T>(a)) + 42;
                                      }
                                      

                                      Where smthng is some other templated nonsense (or simply overloaded), then, I'm sure you'd agree the forward is no longer redundant. :)

                                      Btw. I love how the float version transforms into a fixed point xmm arithmetic with magic constant. Compilers are so smart these days :)

                                      Yeah, true enough. Although you can still catch them missing optimization opportunities from time to time.

                                      @JonB said in Unnecessary const referencing:

                                      Why write this getting-more-complex-all-the-time code if you can ...

                                      What Chris said (... and since this is indeed an academic discussion at this point).

                                      Read and abide by the Qt Code of Conduct

                                      1 Reply Last reply
                                      0

                                      • Login

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