1 | namespace lemon { |
---|
2 | /*! |
---|
3 | |
---|
4 | \page adaptor-references Smart Reference Handling |
---|
5 | |
---|
6 | The adaptor classes are very useful tools in the lemon library. It makes |
---|
7 | possible to create various data view of the current data structures without |
---|
8 | of the copy of them. This makes the lemon programming efficient and |
---|
9 | consederably fast. |
---|
10 | |
---|
11 | \section problem The problem |
---|
12 | |
---|
13 | The adaptors usually use references or pointers to reference to an |
---|
14 | existing data structure. We may use an algorithm in the next way: |
---|
15 | \code |
---|
16 | function_algorithm(adaptor(structure)); |
---|
17 | \endcode |
---|
18 | |
---|
19 | But what about the class algorithms: |
---|
20 | \code |
---|
21 | class_algorithm alg; |
---|
22 | alg.add(adaptor(structure)); |
---|
23 | alg.run(); |
---|
24 | \endcode |
---|
25 | The algorithm store a reference to the given structure. It is a created |
---|
26 | as temporarly and when the expression of the \c add() function is evaluated it |
---|
27 | will be destructed. It is very dangerous handling of the adaptors. |
---|
28 | |
---|
29 | \section solution The solution |
---|
30 | |
---|
31 | We made reference to a temporarly constructed adaptor but we should make |
---|
32 | a copy of the adaptor when it is given as parameter to a class. |
---|
33 | It is not impossible with a little tranformation of the code. |
---|
34 | |
---|
35 | Let's first create some helper class: |
---|
36 | \code |
---|
37 | template <typename _Type, typename Enable = void> |
---|
38 | struct SmartConstReference { |
---|
39 | typedef const _Type& Type; |
---|
40 | }; |
---|
41 | |
---|
42 | template <typename _Type> |
---|
43 | struct SmartConstReference< |
---|
44 | _Type, |
---|
45 | typename enable_if<typename _Type::NeedCopy, void>::type |
---|
46 | > { |
---|
47 | typedef const _Type Type; |
---|
48 | }; |
---|
49 | \endcode |
---|
50 | Then we can place NeedCopy tags in the adaptor classes: |
---|
51 | \code |
---|
52 | template<class M1,class M2> |
---|
53 | class AddMap { |
---|
54 | typename SmartConstReference<M1>::Type m1; |
---|
55 | typename SmartConstReference<M2>::Type m2; |
---|
56 | |
---|
57 | public: |
---|
58 | |
---|
59 | typedef True NeedCopy; |
---|
60 | |
---|
61 | typedef typename M1::Key Key; |
---|
62 | typedef typename M1::Value Value; |
---|
63 | |
---|
64 | AddMap(const M1 &_m1,const M2 &_m2) : m1(_m1), m2(_m2) {}; |
---|
65 | Value operator[](Key k) const {return m1[k]+m2[k];} |
---|
66 | }; |
---|
67 | \endcode |
---|
68 | Then we can transform all of the template map and graph references to |
---|
69 | \c SmartConstReference<Map>::Type or \c SmartConstReference<Graph>::Type. |
---|
70 | This way we copy all of maps and graphs what we should copy but the |
---|
71 | greater data structures are not copied. |
---|
72 | |
---|
73 | \section not-const If the adaptor is not const |
---|
74 | The solution is very similar but it gives an additional problem. |
---|
75 | We make the same \c SmartReferences: |
---|
76 | \code |
---|
77 | template <typename _Type, typename Enable = void> |
---|
78 | struct SmartReference { |
---|
79 | typedef _Type& Type; |
---|
80 | }; |
---|
81 | |
---|
82 | template <typename _Type> |
---|
83 | struct SmartReference< |
---|
84 | _Type, |
---|
85 | typename enable_if<typename _Type::NeedCopy, void>::type |
---|
86 | > { |
---|
87 | typedef _Type Type; |
---|
88 | }; |
---|
89 | \endcode |
---|
90 | Let's create a class that use it: |
---|
91 | \code |
---|
92 | template <typename Map> |
---|
93 | class Algorithm { |
---|
94 | public: |
---|
95 | SmartReference<Map>::Type map; |
---|
96 | Algorithm(Map& _map) : map(_map) {} |
---|
97 | ... |
---|
98 | }; |
---|
99 | \endcode |
---|
100 | But if we want to give an adaptor function as parameter |
---|
101 | it will be a compile error. The adaptor will be created as temporarly |
---|
102 | so it cannot give as reference just as const reference. |
---|
103 | |
---|
104 | Make more helper class: |
---|
105 | \code |
---|
106 | template <typename _Type, typename Enable = void> |
---|
107 | struct SmartParameter { |
---|
108 | typedef _Type& Type; |
---|
109 | }; |
---|
110 | |
---|
111 | template <typename _Type> |
---|
112 | struct SmartParameter< |
---|
113 | _Type, |
---|
114 | typename enable_if<typename _Type::NeedCopy, void>::type |
---|
115 | > { |
---|
116 | typedef const _Type& Type; |
---|
117 | }; |
---|
118 | \endcode |
---|
119 | And the repaired code: |
---|
120 | \code |
---|
121 | template <typename Map> |
---|
122 | class Algorithm { |
---|
123 | public: |
---|
124 | SmartReference<Map>::Type map; |
---|
125 | Algorithm(SmartParameter<Map>::Type _map) : map(_map) {} |
---|
126 | ... |
---|
127 | }; |
---|
128 | \endcode |
---|
129 | But some times it does not help: |
---|
130 | \code |
---|
131 | class Algorithm { |
---|
132 | public: |
---|
133 | ... |
---|
134 | |
---|
135 | template <typename Map> |
---|
136 | void addMap(SmartParameter<Map>::Type _map) { |
---|
137 | ... |
---|
138 | } |
---|
139 | ... |
---|
140 | }; |
---|
141 | \endcode |
---|
142 | Actually, it is a good code but the template parameter should |
---|
143 | be written because it cannot be found out from the parameter type. |
---|
144 | This can be solved with a bigger transformation: |
---|
145 | \code |
---|
146 | class Algorithm { |
---|
147 | public: |
---|
148 | ... |
---|
149 | |
---|
150 | template <typename Map> |
---|
151 | void addMap(const Map& _map) { |
---|
152 | _addMap<SmartParameter<Map>::Type, Map>(_map); |
---|
153 | } |
---|
154 | template <typename Map> |
---|
155 | void addMap(const Map& _map) { |
---|
156 | _addMap<SmartParameter<Map>::Type, Map>(_map); |
---|
157 | } |
---|
158 | |
---|
159 | private: |
---|
160 | template <typename MapParameter, typename Map> |
---|
161 | void _addMap(MapParameter _map) { |
---|
162 | ... |
---|
163 | } |
---|
164 | ... |
---|
165 | }; |
---|
166 | \endcode |
---|
167 | This way we solved the smart referencing problem. |
---|
168 | \author Balazs Dezso |
---|
169 | */ |
---|
170 | } |
---|