2009-05-11 4 views
15

Existe-t-il des ponts permettant de mélanger Qt avec STL et Boost aussi facilement et sans couture que possible?Mélanger Qt avec STL et Boost - existe-t-il des ponts pour le rendre facile?

Ceci est une suite à Mixing Qt and Boost, où aucune réponse spécifique n'a été donnée pour ce faire.

+0

Que faites-vous exactement préoccupé par? En théorie, il ne devrait pas y avoir autant de domaines dans lesquels boost et Qt devraient cohabiter. – Kena

+0

Je n'ai pas encore eu de problèmes car je commence juste à connaître Qt mais avec autant de chevauchement entre le Qt, STL et Boost je suis sûr qu'il y a beaucoup d'endroits où une sorte de marshaling est nécessaire. C'est pareil avec .NET et C++; C'est pourquoi M $ est venu avec la bibliothèque de marshaling. J'essaie d'être préparé pour des choses que je ne peux pas éviter. –

+14

Tout d'abord, la société s'appelle Microsoft, en abrégé MS. Seuls les script kiddies de 13 ans les appellent M $. Deuxièmement, .NET/C++ interop est une bête complètement différente, car vous communiquez entre des plates-formes complètement différentes, du code managé et non managé. QT et Boost sont deux bibliothèques C++, exécutées dans le même processus, utilisant le même environnement d'exécution et tout. Aucun marshalling n'est nécessaire là-bas. – jalf

Répondre

37

De quels ponts avez-vous besoin?

Vous pouvez utiliser toutes les classes de conteneur Qt avec des algorithmes std. La plupart du temps, je préfère les classes de conteneur Qt car je suis sûr qu'elles utilisent l'idiome copy-on-write (opération à temps constant). La fonction foreach de Qt crée une copie du conteneur, donc c'est bien que vous sachiez que c'est une opération à temps constant.

Si le mécanisme du slot de signal Qt doit ralentir, vous pouvez passer à l'alternative de suralimentation. La particularité du signal/slot Qt est la connexion signal/slot entre deux threads.

QtConcurrent fonctionne très bien avec BOOST.Lambda


Pour "partagée" relation parent-enfant que j'utilise cette fonction d'assistance.

template <class Object> 
static boost::shared_ptr<Object> makeSharedObject() 
{ 
    using namespace boost; 
    using namespace boost::lambda; 
    return boost::shared_ptr<Object>( 
     new Object(), 
     bind(&Object::deleteLater, _1)); 
} 

conteneurs Qt ne sont pas pris en charge par Boost.serialize, vous devrez écrire les fonctions de sérialisation vous. J'aimerais un pont entre les classes de streaming Qt et Boost.archive.

Voici mon modèle de sérialisation QList vous pouvez comprendre le reste d'entre eux ...

///\file document is based on "boost/serialization/list.hpp" 

namespace boost { 
    namespace serialization { 

     //--------------------------------------------------------------------------- 
     /// Saves a QList object to a collection 
     template<class Archive, class U > 
     inline void save(Archive &ar, const QList<U> &t, const uint /* file_version */) 
     { 
      boost::serialization::stl::save_collection< Archive, QList<U> >(ar, t); 
     } 

     //--------------------------------------------------------------------------- 
     /// Loads a QList object from a collection 
     template<class Archive, class U> 
     inline void load(Archive &ar, QList<U > &t, const uint /* file_version */) 
     { 
       boost::serialization::stl::load_collection< 
        Archive, 
        QList<U>, 
        boost::serialization::stl::archive_input_seq<Archive, QList<U> >, 
        boost::serialization::stl::no_reserve_imp< QList<U> > >(ar, t); 
     } 

     //--------------------------------------------------------------------------- 
     /// split non-intrusive serialization function member into separate 
     /// non intrusive save/load member functions 
     template<class Archive, class U > 
     inline void serialize(Archive &ar, QList<U> &t, const uint file_version) 
     { 
      boost::serialization::split_free(ar, t, file_version); 
     } 

    } // namespace serialization 
} // namespace boost 

BOOST_SERIALIZATION_COLLECTION_TRAITS(QList) 

Si vous voulez Boost.Se lier à gérer QPointer comme pointeur normal (comme shared_ptr):

namespace boost { 

    template<typename T> T * get_pointer(QPointer<T> const& qPointer) 
    { 
     return qPointer; 
    } 
} 

En utilisant QIODevicestd::stream est nécessaire

namespace boost { 
    namespace iostreams { 

     class IoDeviceSource 
     { 
     public: 
      typedef char char_type; 
      typedef source_tag category; 

      explicit IoDeviceSource(QIODevice& source) 
       : m_source(source) 
      { 
      } 

      std::streamsize read(char* buffer, std::streamsize n) 
      { 
       return return m_source.read(buffer, n); 
      } 
     private: 
      QIODevice& m_source; 
     }; 

     class IoDeviceSink { 

     public: 
      typedef char char_type; 
      typedef sink_tag category; 

      explicit IoDeviceSink(QIODevice& sink) 
       : m_sink(sink) 
      { 
      } 

      std::streamsize write(const char_type* buffer, std::streamsize n) 
      { 
       return m_sink.write(buffer, n); 
      } 

     private: 
      QIODevice &m_sink; 
     }; 

     class IoDeviceDevice { 

     public: 
      typedef char char_type; 
      typedef seekable_device_tag category; 

      explicit IoDeviceDevice(QIODevice& device) 
       :m_device(device) { 
      } 

      std::streamsize write(const char_type *buffer, std::streamsize n) 
      { 
       return m_device.write(buffer, n); 
      } 

      std::streamsize read(char* buffer, std::streamsize n) 
      { 
       return m_device.read(buffer, n); 
      } 

      stream_offset seek(stream_offset off, std::ios_base::seekdir way) 
      { 
       using namespace std; 
       stream_offset next(0); 

       if(way==ios_base::beg) 
       { 
        next = m_device.pos(); 
       } 
       else if(way==ios_base::cur) 
       { 
        next = m_device.pos() + offset; 
       } 
       else if(way==ios_base::end) 
       { 
        next = m_device.size() -1 + offset; 
       } 
       else 
       { 
        throw ios_base::failure("bad seek direction"); 
       } 

       if(!m_device.seek(next)) 
       { 
        throw ios_base::failure("bad seek offset"); 
       } 
       return m_device.pos(); 
      } 

     private:  
      QIODevice &m_device; 
     }; 
    } 
} 

Exemple

#include <iostream> 
#include <QFile> 
#include <boost/iostreams/stream.hpp> 
#include "iodevicestream.h" 

int main(int argc, char *argv[]) 
{ 
    namespace io = boost::iostreams; 

    QVector<int> data; 

    QFile fl("temp.bin"); 
    fl.open(QIODevice::ReadWrite); 
    io::stream<io::IoDeviceDevice> inoutput(fl); 

    std::copy(data.begin(), data.end(), std::ostream_iterator<int>(inoutput, "\n")); 
    inoutput.flush(); 
    inoutput.seekg(0, std::ios_base::beg); 
    std::cout << inoutput; 
    return 0; 
} 
+3

@TimW C'est la meilleure réponse à ce jour ... Merci pour le code réel Connaissant la popularité de Boost, j'espère que l'équipe Qt fera de ce type de passerelle une partie du framework pour éviter aux gens de réinventer la roue. Je pense que cela aiderait aussi à accélérer l'adoption de Qt parmi les développeurs qui travaillent avec Boost, ce qui peut être considéré comme un facteur très important de la popularité de Qt dans certains cercles C++ –

+0

Cela ne devrait pas être le cas avec 'way == ios_base :: beg 'dans' seek' régler 'next' à' offset 'plutôt que 'm_device.pos()'? –

3

Quel est exactement le problème?
Vous pouvez ignorer toutes les classes de collection Qt si vous le souhaitez et utiliser des équivalents STL.
De même, vous pouvez utiliser les librairies de fichiers/réseaux multi-plateforme de Boost.

La principale raison d'utiliser Qt est probablement que boost n'est pas nécessairement largement disponible, en particulier sur les appareils mobiles. Certaines bibliothèques de Boost sont un peu plus compliquées à utiliser que celles de Qt pour des tâches simples.

+0

@mgb Il ne s'agit pas de savoir à qui choisissez et pourquoi mais sur ce qu'il faut faire en utilisant les deux en même temps. Voir la réponse de TimW qui est à peu près ce que j'espérais. –

+0

OK Je vois, vous voudrez peut-être modifier la question pour le reformuler. –

+0

@mgb Exemple: J'ai une classe de base AbstractImage qui doit implémenter une fonction de chargement (QIODevice *). Une sous-classe ImageEXR, qui utilise la lib openEXR pour charger les images EXR. Mais la charge openEXR utilise un istream comme entrée et ne connaît pas Qt. – galinette

2

En général, vous obtiendrez de meilleurs résultats en utilisant QT si vous vous en tenez aux classes de QT Collection plutôt que de nous STL. Il n'y a rien en soi dans Qt, STL ou Boost qui interdirait d'utiliser l'un dans l'autre. Vous devez être prudent lorsque vous utilisez des pointeurs intelligents QT a une relation parent/enfant qui peut prendre en charge la destruction des objets, libérant des objets lorsqu'ils sont sous le contrôle de Qt, ce qui vous fera planter.

+0

il est parfaitement sûr de supprimer un objet Qt. Dans le destructeur de QObject, il se désinscrit de la liste des enfants de son parent. Pas de crash du tout. –

+1

@Evan, il y a quelques pièges ... http://doc.qtsoftware.com/4.5/objecttrees.html en bas. –

+0

J'ai eu des problèmes avec ceci dans le passé. Cela peut être dû au problème de commande noté dans le document ci-dessus. –

Questions connexes