Skip to content

Commit 3b89b67

Browse files
committed
Removing Boost.Variant from Directives
This commit removes the reliance on Boost.Variant, and turns directives into SFINAE aware directives based on the tag of the message. Basically, what we want to happen is for code like the following to fail to compile: basic_message<default_string> m; std::wstring w; m << source(w); The reason it should fail to compile is because the default_string tag tells basic_message to encapsulate std::string, not std::wstring objects for the source. Previously, with the Boost.Variant solution this code would compile and is therefore a serious bug.
1 parent 1ba8079 commit 3b89b67

File tree

2 files changed

+37
-123
lines changed

2 files changed

+37
-123
lines changed

boost/network/message/directives.hpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77
#ifndef __NETWORK_MESSAGE_DIRECTIVES_HPP__
88
#define __NETWORK_MESSAGE_DIRECTIVES_HPP__
99

10-
/** Include all the various directive headers.
11-
*/
12-
1310
#include <boost/network/message/directives/detail/string_directive.hpp>
1411
#include <boost/network/message/directives/header.hpp>
1512
#include <boost/network/message/directives/remove_header.hpp>

boost/network/message/directives/detail/string_directive.hpp

Lines changed: 37 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -10,134 +10,51 @@
1010
#include <boost/variant/variant.hpp>
1111
#include <boost/variant/apply_visitor.hpp>
1212
#include <boost/variant/static_visitor.hpp>
13+
#include <boost/network/support/is_pod.hpp>
14+
#include <boost/utility/enable_if.hpp>
1315
#include <boost/mpl/if.hpp>
1416
#include <boost/mpl/or.hpp>
15-
#include <boost/network/message/directives/detail/string_value.hpp>
1617

17-
namespace boost { namespace network { namespace detail {
18-
19-
/** This directive template technically implements a decorator pattern
20-
* which takes a concrete implementation and uses that as a base. This
21-
* particular directive template requires the Base type to just include
22-
* a nested template named `string_visitor` that takes a single template
23-
* class parameter which is supposed to be a Message class/struct.
24-
*
25-
* A typical directive implementation of the visitor will take a reference
26-
* to a message as the constructor parameter and then performs operations
27-
* on that message.
28-
*
29-
* To create your own string directive, you can use the preprocessor macro
30-
* BOOST_NETWORK_STRING_DIRECTIVE which takes three parameters: the name of
31-
* the directive, a name for the variable to use in the directive visitor,
32-
* and the body to be implemented in the visitor. An example directive for
33-
* setting the source of a message would look something like this given the
34-
* BOOST_NETWORK_STRING_DIRECTIVE macro:
35-
*
36-
* BOOST_NETWORK_STRING_DIRECTIVE(source, source_,
37-
* message.source(source_)
38-
* , message.source=source_);
39-
*
40-
*/
41-
template <class Base>
42-
struct string_directive : public Base {
43-
boost::variant<
44-
string<tags::default_string>::type,
45-
string<tags::default_wstring>::type,
46-
boost::shared_future<string<tags::default_string>::type>,
47-
boost::shared_future<string<tags::default_wstring>::type>
48-
> string_;
49-
50-
explicit string_directive(string<tags::default_string>::type const & input)
51-
: string_(input) {}
52-
explicit string_directive(string<tags::default_wstring>::type const & input)
53-
: string_(input) {}
54-
explicit string_directive(boost::shared_future<string<tags::default_string>::type> const & input)
55-
: string_(input) {}
56-
explicit string_directive(boost::shared_future<string<tags::default_wstring>::type> const & input)
57-
: string_(input) {}
58-
59-
string_directive(string_directive const & other)
60-
: string_(other.string_) {}
61-
62-
template <class Tag, template <class> class Message>
63-
void operator()(Message<Tag> const & message) const {
64-
apply_visitor(typename Base::template string_visitor<Message<Tag> >(message), string_);
65-
}
66-
};
18+
/**
19+
*
20+
* To create your own string directive, you can use the preprocessor macro
21+
* BOOST_NETWORK_STRING_DIRECTIVE which takes three parameters: the name of
22+
* the directive, a name for the variable to use in the directive visitor,
23+
* and the body to be implemented in the visitor. An example directive for
24+
* setting the source of a message would look something like this given the
25+
* BOOST_NETWORK_STRING_DIRECTIVE macro:
26+
*
27+
* BOOST_NETWORK_STRING_DIRECTIVE(source, source_,
28+
* message.source(source_)
29+
* , message.source=source_);
30+
*
31+
*/
6732

33+
#ifndef BOOST_NETWORK_STRING_DIRECTIVE
6834
#define BOOST_NETWORK_STRING_DIRECTIVE(name, value, body, pod_body) \
69-
struct name##_directive_base { \
70-
\
71-
template <class Message> \
72-
struct normal_visitor : boost::static_visitor<> { \
73-
Message const & message; \
74-
explicit normal_visitor(Message const & message) : \
75-
message(message) {} \
76-
void operator()( \
77-
typename boost::network::detail::string_value< \
78-
typename Message::tag \
79-
>::type const & value \
80-
) const { \
81-
body; \
82-
} \
83-
template <class T> void operator()(T const &) const { \
84-
} \
85-
}; \
86-
\
87-
template <class Message> \
88-
struct pod_visitor : boost::static_visitor<> { \
89-
Message const & message; \
90-
explicit pod_visitor(Message const & message) : \
91-
message(message) {} \
92-
void operator()( \
93-
typename boost::network::detail::string_value< \
94-
typename Message::tag \
95-
>::type const & value \
96-
) { \
97-
pod_body; \
98-
} \
99-
template <class T> void operator()(T const &) const { \
100-
} \
101-
}; \
102-
\
103-
template <class Message> \
104-
struct string_visitor : \
105-
mpl::if_< \
106-
is_base_of< \
107-
tags::pod, \
108-
typename Message::tag \
109-
>, \
110-
pod_visitor<Message>, \
111-
normal_visitor<Message> \
112-
>::type \
113-
{ \
114-
typedef typename mpl::if_< \
115-
is_base_of< \
116-
tags::pod, \
117-
typename Message::tag \
118-
>, \
119-
pod_visitor<Message>, \
120-
normal_visitor<Message> \
121-
>::type base; \
122-
explicit string_visitor(Message const & message): \
123-
base(message) {} \
124-
string_visitor(string_visitor const & other): \
125-
base(other) {} \
126-
using base::operator(); \
127-
}; \
35+
template <class ValueType> \
36+
struct name##_directive { \
37+
ValueType const & value; \
38+
explicit name##_directive(ValueType const & value_) \
39+
: value(value_) {} \
40+
name##_directive(name##_directive const & other) \
41+
: value(other.value) {} \
42+
template <class Tag, template <class> class Message> \
43+
typename enable_if<is_pod<Tag>, void>::type \
44+
operator()(Message<Tag> & message) const { \
45+
pod_body; \
46+
} \
47+
template <class Tag, template <class> class Message> \
48+
typename enable_if<mpl::not_<is_pod<Tag> >, void>::type \
49+
operator()(Message<Tag> & message) const { \
50+
body; \
51+
} \
12852
}; \
12953
\
130-
typedef boost::network::detail::string_directive<name##_directive_base> \
131-
name##_directive; \
132-
template <class T> inline name##_directive const \
54+
template <class T> inline name##_directive<T> \
13355
name (T const & input) { \
134-
return name##_directive(input); \
56+
return name##_directive<T>(input); \
13557
}
136-
137-
} /* detail */
138-
139-
} /* network */
140-
141-
} /* boost */
58+
#endif /* BOOST_NETWORK_STRING_DIRECTIVE */
14259

14360
#endif /* BOOST_NETWORK_MESSAGE_DIRECTIVES_DETAIL_STRING_DIRECTIVE_HPP_20100915 */

0 commit comments

Comments
 (0)