deba@1418: namespace lemon { deba@1418: /*! deba@1418: deba@1418: \page adaptor-references Smart Reference Handling deba@1418: deba@1418: The adaptor classes are very useful tools in the lemon library. It makes deba@1418: possible to create various data view of the current data structures without deba@1418: of the copy of them. This makes the lemon programming efficient and deba@1418: consederably fast. deba@1418: deba@1418: \section problem The problem deba@1418: deba@1418: The adaptors usually use references or pointers to reference to an alpar@1591: existing data structure. We may use an algorithm in the following way: deba@1418: \code deba@1418: function_algorithm(adaptor(structure)); deba@1418: \endcode deba@1418: deba@1418: But what about the class algorithms: deba@1418: \code deba@1418: class_algorithm alg; deba@1418: alg.add(adaptor(structure)); deba@1418: alg.run(); deba@1418: \endcode deba@1418: The algorithm store a reference to the given structure. It is a created deba@1418: as temporarly and when the expression of the \c add() function is evaluated it deba@1418: will be destructed. It is very dangerous handling of the adaptors. deba@1418: deba@1418: \section solution The solution deba@1418: deba@1418: We made reference to a temporarly constructed adaptor but we should make deba@1418: a copy of the adaptor when it is given as parameter to a class. deba@1418: It is not impossible with a little tranformation of the code. deba@1418: deba@1418: Let's first create some helper class: deba@1418: \code deba@1418: template deba@1418: struct SmartConstReference { deba@1418: typedef const _Type& Type; deba@1418: }; deba@1418: deba@1418: template deba@1418: struct SmartConstReference< deba@1418: _Type, deba@1418: typename enable_if::type deba@1418: > { deba@1418: typedef const _Type Type; deba@1418: }; deba@1418: \endcode deba@1418: Then we can place NeedCopy tags in the adaptor classes: deba@1418: \code deba@1418: template deba@1418: class AddMap { deba@1418: typename SmartConstReference::Type m1; deba@1418: typename SmartConstReference::Type m2; deba@1418: deba@1418: public: deba@1418: deba@1418: typedef True NeedCopy; deba@1418: deba@1418: typedef typename M1::Key Key; deba@1418: typedef typename M1::Value Value; deba@1418: deba@1418: AddMap(const M1 &_m1,const M2 &_m2) : m1(_m1), m2(_m2) {}; deba@1418: Value operator[](Key k) const {return m1[k]+m2[k];} deba@1418: }; deba@1418: \endcode deba@1418: Then we can transform all of the template map and graph references to deba@1418: \c SmartConstReference::Type or \c SmartConstReference::Type. deba@1418: This way we copy all of maps and graphs what we should copy but the deba@1418: greater data structures are not copied. deba@1418: deba@1418: \section not-const If the adaptor is not const deba@1418: The solution is very similar but it gives an additional problem. deba@1418: We make the same \c SmartReferences: deba@1418: \code deba@1418: template deba@1418: struct SmartReference { deba@1418: typedef _Type& Type; deba@1418: }; deba@1418: deba@1418: template deba@1418: struct SmartReference< deba@1418: _Type, deba@1418: typename enable_if::type deba@1418: > { deba@1418: typedef _Type Type; deba@1418: }; deba@1418: \endcode deba@1418: Let's create a class that use it: deba@1418: \code deba@1418: template deba@1418: class Algorithm { deba@1418: public: deba@1418: SmartReference::Type map; deba@1418: Algorithm(Map& _map) : map(_map) {} deba@1418: ... deba@1418: }; deba@1418: \endcode deba@1418: But if we want to give an adaptor function as parameter deba@1418: it will be a compile error. The adaptor will be created as temporarly deba@1418: so it cannot give as reference just as const reference. deba@1418: deba@1418: Make more helper class: deba@1418: \code deba@1418: template deba@1418: struct SmartParameter { deba@1418: typedef _Type& Type; deba@1418: }; deba@1418: deba@1418: template deba@1418: struct SmartParameter< deba@1418: _Type, deba@1418: typename enable_if::type deba@1418: > { deba@1418: typedef const _Type& Type; deba@1418: }; deba@1418: \endcode deba@1418: And the repaired code: deba@1418: \code deba@1418: template deba@1418: class Algorithm { deba@1418: public: deba@1418: SmartReference::Type map; deba@1418: Algorithm(SmartParameter::Type _map) : map(_map) {} deba@1418: ... deba@1418: }; deba@1418: \endcode deba@1418: But some times it does not help: deba@1418: \code deba@1418: class Algorithm { deba@1418: public: deba@1418: ... deba@1418: deba@1418: template deba@1418: void addMap(SmartParameter::Type _map) { deba@1418: ... deba@1418: } deba@1418: ... deba@1418: }; deba@1418: \endcode deba@1418: Actually, it is a good code but the template parameter should deba@1418: be written because it cannot be found out from the parameter type. deba@1418: This can be solved with a bigger transformation: deba@1418: \code deba@1418: class Algorithm { deba@1418: public: deba@1418: ... deba@1418: deba@1418: template deba@1418: void addMap(const Map& _map) { deba@1418: _addMap::Type, Map>(_map); deba@1418: } deba@1418: template deba@1418: void addMap(const Map& _map) { deba@1418: _addMap::Type, Map>(_map); deba@1418: } deba@1418: deba@1418: private: deba@1418: template deba@1418: void _addMap(MapParameter _map) { deba@1418: ... deba@1418: } deba@1418: ... deba@1418: }; deba@1418: \endcode deba@1418: This way we solved the smart referencing problem. deba@1418: \author Balazs Dezso deba@1418: */ deba@1418: }