Skip to content

Commit 5c0246b

Browse files
committed
Adding more details with the tag metafunction overhaul.
1 parent c106b79 commit 5c0246b

File tree

2 files changed

+82
-19
lines changed

2 files changed

+82
-19
lines changed

libs/network/doc/tag_metafunctions.rst

Lines changed: 78 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ defining type traits. In the :mod:`cpp-netlib` however the type traits
1313
are defined on opaque tag types which serve to associate results to a
1414
family of metafunctions.
1515

16+
Template Specialization
17+
-----------------------
18+
1619
To illustrate this point, let's define a tag ``default_`` which we use
1720
to denote the default implementation of a certain type ``foo``. For
1821
instance we decide that the default string type we will use for
@@ -38,7 +41,78 @@ translate to:
3841
typedef std::string type;
3942
};
4043

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
42116
``string`` and pass the tag type parameter to determine what to use as
43117
the string type in the context of the type ``foo``. In code this would
44118
translate into:
@@ -55,10 +129,9 @@ translate into:
55129
Using this approach we can support different types of strings for
56130
different tags on the type ``foo``. In case we want to use a different
57131
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.
62135

63136
The approach also allows for the control of the structure and features
64137
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
97170
invariants. This keeps the whole extension mechanism static and yet
98171
flexible.
99172

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.

libs/network/doc/whats_new.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
---------------------
99

1010
* Radical documentation overhaul
11-
* Asynchronous HTPP client
11+
* Asynchronous HTTP client
12+
* Tag dispatch overhaul, using Boost.MPL
13+
* HTTP Client Facade refactoring
14+
* Bug fixes for HTTP 1.1 response parsing
1215

1316
:mod:`cpp-netlib` 0.6
1417
---------------------

0 commit comments

Comments
 (0)