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. Template: Force const parameter
QtWS25 Last Chance

Template: Force const parameter

Scheduled Pinned Locked Moved Solved C++ Gurus
c++template
13 Posts 4 Posters 5.0k Views
  • 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.
  • J Offline
    J Offline
    Joel Bodenmann
    wrote on 26 Aug 2016, 10:36 last edited by Joel Bodenmann
    #1

    Let's assume I have the following class:

    class LibraryMimeData : public QMimeData
    {
        Q_OBJECT
    
    public:
        LibraryMimeData() = default;
        virtual ~LibraryMimeData() override = default;
    
        virtual QStringList formats() const;
        virtual bool hasFormat(const QString& mimeType) const;
    
        void setLibraryItems(QList<const LibraryItem*> libraryItems);
        QList<const LibraryItem*> libraryItems() const;
    
        template<class T>
        QList<T> libraryItems() const
        {
            QList<T> list;
    
            for (const LibraryItem* libraryItem : _libraryItems) {
                T item = dynamic_cast<T>(libraryItem);
                if (item) {
                    list << item;
                }
            }
    
            return list;
        }
    
    private:
        Q_DISABLE_COPY(LibraryMimeData)
    
        QList<const LibraryItem*> _libraryItems;
    };
    

    LibraryItem is a base class with different subclasses. The class shown above is used to pass sets of those items around during drag'n'drop operations. The method QList<T> LibraryItemMimeData::libraryItems() const has been added for convenience to allow the receiver of the mime data to retrieve a list only containing items of a specific type. As all those "specific types" inherit from the LibraryItem base class, I am just using dynamic_cast here (note: qobject_cast wouldn't work because LibraryItem doesn't inherit from QObject).

    My question is: Can I force the caller of that method to only use template types/parameters (the T thing) that are const pointers? Right now he could request a list of QList<MyLibraryItemSubclass*>. However, as the LibraryItemMimeData class only has const pointers to those library items itself, it can only return QList<const MyLibraryItemSubclass*>.

    Any other comments regarding that piece of code are more than welcomed :)

    Industrial process automation software: https://simulton.com
    Embedded Graphics & GUI library: https://ugfx.io

    1 Reply Last reply
    0
    • K Offline
      K Offline
      kshegunov
      Moderators
      wrote on 26 Aug 2016, 11:38 last edited by
      #2

      I haven't tried it, but:

      template<class T>
      QList<const T *> libraryItems() const
      {
          // ...
          QList<const T *> list;
          // ...
      }
      

      ?

      Read and abide by the Qt Code of Conduct

      1 Reply Last reply
      0
      • J Offline
        J Offline
        Joel Bodenmann
        wrote on 26 Aug 2016, 11:41 last edited by Joel Bodenmann
        #3

        The problem with that is that then the user/caller of that method has to write code like this:

        QList<const MyLibraryItem*> myLibraryItems = mimeData->libraryItems<MyLibraryItem*>();
        

        In my opinion that is just a no-go. You'd expect the two template parameters to be the same in that assignment.

        Industrial process automation software: https://simulton.com
        Embedded Graphics & GUI library: https://ugfx.io

        K 1 Reply Last reply 26 Aug 2016, 11:45
        0
        • J Joel Bodenmann
          26 Aug 2016, 11:41

          The problem with that is that then the user/caller of that method has to write code like this:

          QList<const MyLibraryItem*> myLibraryItems = mimeData->libraryItems<MyLibraryItem*>();
          

          In my opinion that is just a no-go. You'd expect the two template parameters to be the same in that assignment.

          K Offline
          K Offline
          kshegunov
          Moderators
          wrote on 26 Aug 2016, 11:45 last edited by
          #4

          @Joel-Bodenmann
          Actually:

          QList<const MyLibraryItem *> myLibraryItems = mimeData->libraryItems<MyLibraryItem>();
          

          But yes, they differ. Whether or not it's acceptable it's up to you, I know of no other way.

          PS.
          I think a fat notice in the docs should be just enough. This isn't c++11 so what's on the left can be different from what's on the right (i.e. there's no auto confusing code). It's still valid to write:

          QWidget * button = new QToolButton();
          

          Read and abide by the Qt Code of Conduct

          1 Reply Last reply
          0
          • C Offline
            C Offline
            Chris Kawa
            Lifetime Qt Champion
            wrote on 26 Aug 2016, 19:46 last edited by Chris Kawa
            #5

            Can I force the caller of that method to only use template types/parameters (the T thing) that are const pointers?

            I'll just assume you really meant pointers to const, because const pointer would be LibraryItem* const, which is entirely different beast.

            This is one of those cases where templates come really handy. Here's a stripped down implementation:

            class LibraryMimeData
            {
            private:
                QList<const LibraryItem*> _libraryItems;
            
                // this general type will get rid of non-pointer and pointer to non-const types
                template<typename T, bool is_pointer_to_const> struct Foo {
                    static inline QList<T> convert(const QList<const LibraryItem*>& items) = delete;
                };
            
                //the specialized type will only accept pointer to const types
                template<typename T> struct Foo<T, true> {
                    static inline QList<T> convert(const QList<const LibraryItem*>& items)
                    {
                        return /* DO THE CONVERSION */;
                    }
                };
            
            public:
                //and here's a public interface
                template<typename T> QList<T> libraryItems() const {
                    return Foo<T, std::is_pointer<T>::value && std::is_const<std::remove_pointer<T>::type>::value>::convert(_libraryItems);
                }
            };
            

            This way it will work for pointer to const types and will give a lovely error about using deleted function for all others.

            K 1 Reply Last reply 27 Aug 2016, 00:42
            5
            • C Chris Kawa
              26 Aug 2016, 19:46

              Can I force the caller of that method to only use template types/parameters (the T thing) that are const pointers?

              I'll just assume you really meant pointers to const, because const pointer would be LibraryItem* const, which is entirely different beast.

              This is one of those cases where templates come really handy. Here's a stripped down implementation:

              class LibraryMimeData
              {
              private:
                  QList<const LibraryItem*> _libraryItems;
              
                  // this general type will get rid of non-pointer and pointer to non-const types
                  template<typename T, bool is_pointer_to_const> struct Foo {
                      static inline QList<T> convert(const QList<const LibraryItem*>& items) = delete;
                  };
              
                  //the specialized type will only accept pointer to const types
                  template<typename T> struct Foo<T, true> {
                      static inline QList<T> convert(const QList<const LibraryItem*>& items)
                      {
                          return /* DO THE CONVERSION */;
                      }
                  };
              
              public:
                  //and here's a public interface
                  template<typename T> QList<T> libraryItems() const {
                      return Foo<T, std::is_pointer<T>::value && std::is_const<std::remove_pointer<T>::type>::value>::convert(_libraryItems);
                  }
              };
              

              This way it will work for pointer to const types and will give a lovely error about using deleted function for all others.

              K Offline
              K Offline
              kshegunov
              Moderators
              wrote on 27 Aug 2016, 00:42 last edited by
              #6

              Ahahah, I needed a couple of reads to get it. It's quite nifty, albeit pretty verbose.

              Read and abide by the Qt Code of Conduct

              1 Reply Last reply
              0
              • C Offline
                C Offline
                Chris Kawa
                Lifetime Qt Champion
                wrote on 27 Aug 2016, 00:58 last edited by
                #7

                @kshegunov Yeah, templates usually do that when it's not you who wrote them ;) I usually steer away from them if I can but when you need to deal with type system and avoid runtime overhead they are a very flexible tool.
                The verbose part is an implementation detail. Commented well and renamed to something better than Foo can live happily in a codebase. The user facing function has a nice clean signature.

                K 1 Reply Last reply 27 Aug 2016, 01:04
                0
                • C Chris Kawa
                  27 Aug 2016, 00:58

                  @kshegunov Yeah, templates usually do that when it's not you who wrote them ;) I usually steer away from them if I can but when you need to deal with type system and avoid runtime overhead they are a very flexible tool.
                  The verbose part is an implementation detail. Commented well and renamed to something better than Foo can live happily in a codebase. The user facing function has a nice clean signature.

                  K Offline
                  K Offline
                  kshegunov
                  Moderators
                  wrote on 27 Aug 2016, 01:04 last edited by kshegunov
                  #8

                  @Chris-Kawa said in Template: Force const parameter:

                  I usually steer away from them

                  Me too, which you can deduce from my simplistic answer :P
                  They're just marginally better than the preprocessor ... code writing code always perplexes me, I must admit ...

                  PS.
                  I must also give you credit for the partial specialization trick ... never would've come up with it myself.

                  Read and abide by the Qt Code of Conduct

                  1 Reply Last reply
                  0
                  • C Offline
                    C Offline
                    Chris Kawa
                    Lifetime Qt Champion
                    wrote on 27 Aug 2016, 01:16 last edited by Chris Kawa
                    #9

                    They're just marginally better than the preprocessor

                    Awww, that's hurtful to the templates :) Preprocessor is just glorified find/replace machinery. Templates are a full blown, type safe, statically checked sub-language. Combined with constexpr they really have a Death-Star-like power (with similar caveats ;) )
                    I remember when I wrote template based compile time quick sort back in the days. Sure it resulted in a 500Mb executable and crashed the compiler for input arrays larger then a dozen elements but it was constant O(1) time for any input :P
                    Sorry for offtopic. Nostalgia took me over ;)

                    1 Reply Last reply
                    1
                    • J Offline
                      J Offline
                      Joel Bodenmann
                      wrote on 27 Aug 2016, 12:01 last edited by
                      #10

                      @Chris-Kawa said in Template: Force const parameter:

                      I'll just assume you really meant pointers to const, because const pointer would be LibraryItem* const, which is entirely different beast.

                      Your assumption is correct. Sorry for using the wrong terminology. I'll blame not-getting-enough-sleep for it :p

                      @Chris-Kawa said in Template: Force const parameter:

                      Here's a stripped down implementation:

                      Oh boy... This is going to take a while (and lots of reading) for me to understand it. But I appreciate your efforts. Also, experience tells me that all code examples you write/post on this forum always just work, so huge Thank you! although I don't understand it yet :p

                      @Chris-Kawa said in Template: Force const parameter:

                      I remember when I wrote template based compile time quick sort back in the days. Sure it resulted in a 500Mb executable and crashed the compiler for input arrays larger then a dozen elements but it was constant O(1) time for any input :P

                      Is there any blog post / white paper you can link to? Sounds interesting :)

                      Industrial process automation software: https://simulton.com
                      Embedded Graphics & GUI library: https://ugfx.io

                      1 Reply Last reply
                      0
                      • C Offline
                        C Offline
                        Chris Kawa
                        Lifetime Qt Champion
                        wrote on 27 Aug 2016, 12:22 last edited by
                        #11

                        I guess the line that need the most explaining is this one:

                        return Foo<T, std::is_pointer<T>::value && std::is_const<std::remove_pointer<T>::type>::value>::convert(_libraryItems);
                        

                        All the std magic is just a verbose way of saying "is T a pointer and does it point to a const value" so it's pretty much
                        Foo<T, true>::convert(_libraryItems) for types that qualify and
                        Foo<T, false>::convert(_libraryItems) for those that don't.

                        Foo<T, false> will call into thet deleted specialization and Foo<T, true> into the real conversion.

                        std::is_pointer<T>::value - this is true for pointers, false for others
                        std::remove_pointer<T>::type - for any given pointer type it's a typedef for the pointed to type e.g for T being int* it's int.
                        std::is_const<X>::value - this is true for const types and false for others

                        Is there any blog post / white paper you can link to? Sounds interesting :)

                        It was a class assignment over a decade ago. I'm sure the topic has a vast coverage, but I can't give you any links because it's simply useless in practice and I hadn't any interest in it after completing it.

                        1 Reply Last reply
                        1
                        • V Offline
                          V Offline
                          VRonin
                          wrote on 31 Aug 2016, 16:29 last edited by
                          #12

                          I'm definitely in the wrong section of the forum given my knowledge of the language but why wouldn't a simple static_assert work here?

                          template<class T>
                              QList<T> libraryItems() const
                              {
                          static_assert(std::is_pointer<T>::value && std::is_const<std::remove_pointer<T>::type>::value,"You can only use const pointers as template parameters");
                                  QList<T> list;
                          \\ etc
                          

                          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                          ~Napoleon Bonaparte

                          On a crusade to banish setIndexWidget() from the holy land of Qt

                          1 Reply Last reply
                          2
                          • C Offline
                            C Offline
                            Chris Kawa
                            Lifetime Qt Champion
                            wrote on 31 Aug 2016, 17:28 last edited by
                            #13

                            @VRonin said in Template: Force const parameter:

                            why wouldn't a simple static_assert work here?

                            It definitely would.

                            1 Reply Last reply
                            0

                            9/13

                            27 Aug 2016, 01:16

                            • Login

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