@@ -13,6 +13,9 @@ defining type traits. In the :mod:`cpp-netlib` however the type traits
13
13
are defined on opaque tag types which serve to associate results to a
14
14
family of metafunctions.
15
15
16
+ Template Specialization
17
+ -----------------------
18
+
16
19
To illustrate this point, let's define a tag ``default_`` which we use
17
20
to denote the default implementation of a certain type ``foo``. For
18
21
instance we decide that the default string type we will use for
@@ -38,7 +41,78 @@ translate to:
38
41
typedef std::string type;
39
42
};
40
43
41
- Then in the definition of the type ``foo`` we use this type function
44
+ Template Metaprogramming
45
+ ------------------------
46
+
47
+ Starting with version 0.7, the tag dispatch mechanism changed slightly to use
48
+ Boost.MPL_. The idea is still the same, although we can get a little smarter
49
+ than just using template specializations. Instead of just defining an opaque
50
+ type ``default_``, we use the Boost.MPL equivalent of a vector to define which
51
+ root types of properties this ``default_`` tag supports. The idea is to make the
52
+ opaque type ``default_`` inherit property tags which the library supports
53
+ internally as definite extension points.
54
+
55
+ .. _Boost.MPL: http://www.boost.org/libs/mpl/index.html
56
+
57
+ Our definition of the ``default_`` tag will then look something like the
58
+ following:
59
+
60
+ .. code-block:: c++
61
+
62
+ typedef mpl::vector<default_string> default_tags;
63
+
64
+ template <class Tag>
65
+ struct components;
66
+
67
+ typedef mpl::inherit_linearly<
68
+ default_tags,
69
+ mpl::inherit<mpl::placeholders::_1, mpl::placeholders::_2>
70
+ >::type default_;
71
+
72
+ template <class Tag>
73
+ struct components<default_> {
74
+ typedef default_tags type;
75
+ };
76
+
77
+ In the above listing, ``default_string`` is what we call a "root" tag which is
78
+ meant to be combined with other "root" tags to form composite tags. In this case
79
+ our composite tag is the tag ``default_``. There are a number of these "root"
80
+ tags that :mod:`cpp-netlib` provides. These are in the namespace
81
+ ``boost::network::tags`` and are defined in ``boost/network/tags.hpp``.
82
+
83
+ Using this technique we change slightly our definition of the ``string``
84
+ metafunction class into this:
85
+
86
+ .. code-block:: c++
87
+
88
+ template <class Tag>
89
+ struct unsupported_tag;
90
+
91
+ template <class Tag>
92
+ struct string :
93
+ mpl::if_<
94
+ is_base_of<
95
+ Tag,
96
+ tags::default_string
97
+ >,
98
+ std::string,
99
+ unsupported_tag<Tag>
100
+ >
101
+ {};
102
+
103
+ Notice that we don't have the typedef for ``type`` in the body of ``string``
104
+ anymore, but we do inherit from ``mpl::if_``. Since ``mpl::if_`` is a template
105
+ metafunction itself, it contains a definition of the resulting ``type`` which
106
+ ``string`` inherits.
107
+
108
+ You can see the real definition of the ``string`` metafunction in
109
+ ``boost/network/traits/string.hpp``.
110
+
111
+ Using Tags
112
+ ----------
113
+
114
+ Once we have the defined tag, we can then use this in the definition of our
115
+ types. In the definition of the type ``foo`` we use this type function
42
116
``string`` and pass the tag type parameter to determine what to use as
43
117
the string type in the context of the type ``foo``. In code this would
44
118
translate into:
@@ -55,10 +129,9 @@ translate into:
55
129
Using this approach we can support different types of strings for
56
130
different tags on the type ``foo``. In case we want to use a different
57
131
type of string for the tag ``default_`` we only change the
58
- specialization of ``string<default_>``. In the other case that we want
59
- to use a different tag to define the functionality of ``foo``, all we
60
- have to do is implement specializations of the type functions like
61
- ``string`` for that different tag.
132
+ composition of the ``string_tags`` MPL vector. For example, in :mod:`cpp-netlib`
133
+ there is a root tag ``default_wstring`` which causes the ``string`` metafunction
134
+ to define ``std::wstring`` as the resulting type.
62
135
63
136
The approach also allows for the control of the structure and features
64
137
of types like ``foo`` based on the specialization of the tag. Whole
@@ -97,16 +170,3 @@ definition of extension points that ensures type-safety and
97
170
invariants. This keeps the whole extension mechanism static and yet
98
171
flexible.
99
172
100
- One drawback with this approach is the verbosity at which extensions
101
- and specializations are to be done which introduces additional
102
- pressure on the compiler at compile-time computations. Because this
103
- technique relies heavily on the C++ template mechanism, compile times
104
- may be greatly increased.
105
-
106
- The potential for tag and implementation explosion is also high. If
107
- the implementor is not careful in controlling the number of tags and
108
- type functions that take the tag as an input, it can get out of hand
109
- quickly. The suggestion is to define acceptable defaults and leverage
110
- re-use of existing tags as much as possible. Using Boost.MPL data
111
- structures like map's and/or control structures like ``if_`` and
112
- ``switch_`` can also help with heavily-used type functions.