gravatar
alpar (Alpar Juttner)
alpar@cs.elte.hu
Improvements in named-param.dox
0 1 0
default
1 file changed with 44 insertions and 58 deletions:
↑ Collapse diff ↑
Ignore white space 12 line context
... ...
@@ -19,27 +19,20 @@
19 19
/*!
20 20

	
21 21
\page named-param Named Parameters
22 22

	
23 23
\section named-func-param Named Function Parameters
24 24

	
25
C++ makes it possible to use default parameter values when calling a
26
function. In such a case we do not have to give value for parameters,
27
the program will use the default ones.  Unfortunately sometimes this
28
is not enough. If we do not want to give values for all the
29
parameters, only for some of them we come across problems, because an
30
arbitrary set of parameters cannot be omitted. On the other hand
31
parameters have a fixed order in the head of the function.  C++ can
32
apply the default values only in the back of the order, if we do not
33
give other value for them.  So we can not give the function for
34
example the value of the first, and the third parameter, expecting
35
that the program will aplly the default value for the second
36
parameter.  However sometimes we would like to use some functinos
37
exactly in this way. With a crafty trick and with some little
38
inconvenience this is possible. We have implemented this little trick
39
as an example below.
25
Several modern languages provide a convenient way to refer the
26
function parameters by name also when you call the function. It is
27
especially comfortable in case of a function having tons of parameters
28
with natural default values. Sadly, C++ lack this amenity. 
29

	
30
However, with a crafty trick and with some little
31
inconvenience, it is possible to emulate is.
32
The example below shows how to do it.
40 33

	
41 34
\code
42 35
class namedFn 
43 36
{
44 37
  int _id;
45 38
  double _val;
... ...
@@ -49,69 +42,68 @@
49 42
  namedFn() : _id(0), _val(1), _dim(2) {}
50 43
  namedFn& id(int p)     { _id  = p ; return *this; }
51 44
  namedFn& val(double p) { _val = p ; return *this; }
52 45
  namedFn& dim(int p)    { _dim = p ; return *this; }
53 46

	
54 47
  run() {
55
    printf("Here is the function itself.");
48
  std::cout << "Here comes the function itself\n" <<
49
            << "With parameters "
50
            << _id << ", " << _val << ", " << _dim << std::endl; 
56 51
  }
57 52
};
58 53
\endcode
59 54

	
55
Then you can use it like this.
60 56

	
61
The usage is the following.
62

	
63
We have to define a class, let's call it \c namedFn.  Let us assume that
64
we would like to use a parameter, called \c X. In the \c namedFn class we
65
have to define an \c _X attribute, and a function \c X. The function
66
expects a parameter with the type of \c _X, and sets the value of
67
\c _X. After setting the value the function returns the class itself. The
68
class also have to have a function, called for example <tt>run()</tt>, we have
69
to implement here the original function itself. The constructor of the
70
class have to give all the attributes like \c _X the default values of
71
them.
72

	
73
If we instantiate this class, the default values will be set for the
74
attributes (originally the parameters), initially. If we call function
75
\c X, we get a class with the modified parameter value of
76
\c X. Therefore we can modify any parameter-value, independently from the
77
order. To run the algorithm we have to call the <tt>run()</tt> function at the
78
end of the row.
79

	
80
Example:
81 57
\code
82 58
namedFn().id(3).val(2).run();
83 59
\endcode
84 60

	
61
The trick is obvious, each "named parameter" changes one component of
62
the underlying class, then gives back a reference to it. Finally,
63
<tt>run()</tt> executes the algorithm itself.
64

	
85 65
\note Although it is a class, namedFn is used pretty much like as it were
86
a function. That it why it is called namedFn and not \c NamedFn.
66
a function. That it why we called it namedFn instead of \c NamedFn.
87 67

	
88
\note In fact, the final <tt>.run()</tt> could be made unnecessary if the
89
actual function code were put in the destructor instead. This however would make
90
hard to implement functions with return values, and would also make the
91
implementation of \ref named-templ-func-param "named template parameters"
92
very problematic. <b>Therefore, by convention, <tt>.run()</tt> must be used
93
to explicitly execute function having named parameters in Lemon.</b>
68
\note In fact, the final <tt>.run()</tt> could be made unnecessary,
69
because the algorithm could also be implemented in the destructor of
70
\c namedFn instead. This however would make it impossible to implement
71
functions with return values, and would also cause serious problems when
72
implementing \ref named-templ-func-param "named template parameters".
73
<b>Therefore, by convention, <tt>.run()</tt> must be used
74
explicitly to execute a function having named parameters
75
everywhere in LEMON.</b>
94 76

	
77
\section named-templ-func-param Named Function Template Parameters
78

	
79
A named parameter can also be a template functions. The usage is
80
exactly the same, but the implementation behind is a kind of black
81
magic and they are the dirtiest part of the LEMON code.
82

	
83
You will probably never need to know how it works, but if you really
84
committed, have a look at \ref lemon/graph_to_eps.h for an example.
95 85

	
96 86
\section traits-classes Traits Classes
97 87

	
98
The procedure above can also be applied when defining classes. In this
99
case the type of the attributes can be changed.  Initially we have to
100
define a class with the default attribute types. This is the so called
101
Traits Class. Later on the types of these attributes can be changed,
102
as described below. In our software \ref lemon::DijkstraDefaultTraits is an
103
example of how a traits class looks like.
88
A similar game can also be played when defining classes. In this case
89
the type of the class attributes can be changed. Initially we have to
90
define a special class called <em>Traits Class</em> defining the
91
default type of the attributes. Then the types of these attributes can
92
be changed in the same way as described in the next section.
93

	
94
See \ref lemon::DijkstraDefaultTraits for an
95
example how a traits class implementation looks like.
104 96

	
105 97
\section named-templ-param Named Class Template Parameters
106 98

	
107 99
If we would like to change the type of an attribute in a class that
108 100
was instantiated by using a traits class as a template parameter, and
109
the class contains named parameters, we do not have to reinstantiate
110
the class with new traits class. Instead of that, adaptor classes can
111
be used like in the following cases.
101
the class contains named parameters, we do not have to instantiate again
102
the class with new traits class, but instead adaptor classes can
103
be used as shown in the following example.
112 104

	
113 105
\code
114 106
Dijkstra<>::SetPredNodeMap<NullMap<Node,Node> >::Create
115 107
\endcode
116 108

	
117 109
It can also be used in conjunction with other named template
... ...
@@ -121,13 +113,7 @@
121 113
Dijkstra<>::SetDistMap<MyMap>::SetPredMap<NullMap<Node,Edge> >::Create
122 114
\endcode
123 115

	
124 116
The result will be an instantiated Dijkstra class, in which the
125 117
DistMap and the PredMap is modified.
126 118

	
127
\section named-templ-func-param Named Function Template Parameters
128

	
129
If the class has so called wizard functions, the new class with the
130
modified tpye of attributes can be returned by the appropriate wizard
131
function. The usage of these wizard functions is the following:
132

	
133 119
*/
0 comments (0 inline)