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 2.9k 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 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 Offline
        JonBJ Offline
        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 Offline
              JonBJ Offline
              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 Online
                    Christian EhrlicherC Online
                    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 Offline
                        JonBJ Offline
                        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 Offline
                              JonBJ Offline
                              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