Skip to content

Commit 4e37816

Browse files
authored
Merge pull request #325 from gummif/gfa/msg-range-ctor
Problem: message_t ctor for ranges too greedy
2 parents 0672e31 + f412ea9 commit 4e37816

File tree

5 files changed

+162
-7
lines changed

5 files changed

+162
-7
lines changed

tests/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ add_executable(
2525
poller.cpp
2626
active_poller.cpp
2727
multipart.cpp
28-
monitor.cpp
28+
monitor.cpp
29+
utilities.cpp
2930
)
3031

3132
add_dependencies(unit_tests catch)

tests/message.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ TEST_CASE("message constructor with iterators", "[message]")
4848
CHECK(0 == memcmp(data, hi_msg.data(), 2));
4949
}
5050

51+
TEST_CASE("message constructor with size", "[message]")
52+
{
53+
const zmq::message_t msg(5);
54+
CHECK(msg.size() == 5);
55+
}
56+
5157
TEST_CASE("message constructor with buffer and size", "[message]")
5258
{
5359
const std::string hi(data);

tests/socket.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ TEST_CASE("socket send recv message_t", "[socket]")
184184
s2.bind("inproc://test");
185185
s.connect("inproc://test");
186186

187-
zmq::message_t smsg(size_t{10});
187+
zmq::message_t smsg(10);
188188
const auto res_send = s2.send(smsg, zmq::send_flags::none);
189189
CHECK(res_send);
190190
CHECK(*res_send == 10);

tests/utilities.cpp

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#include <catch.hpp>
2+
#include <zmq.hpp>
3+
4+
#ifdef ZMQ_CPP11
5+
6+
namespace test_ns
7+
{
8+
struct T_nr
9+
{
10+
};
11+
struct T_mr
12+
{
13+
void *begin() const noexcept { return nullptr; }
14+
void *end() const noexcept { return nullptr; }
15+
};
16+
struct T_fr
17+
{
18+
};
19+
void *begin(const T_fr &) noexcept
20+
{
21+
return nullptr;
22+
}
23+
void *end(const T_fr &) noexcept
24+
{
25+
return nullptr;
26+
}
27+
struct T_mfr
28+
{
29+
void *begin() const noexcept { return nullptr; }
30+
void *end() const noexcept { return nullptr; }
31+
};
32+
void *begin(const T_mfr &) noexcept
33+
{
34+
return nullptr;
35+
}
36+
void *end(const T_mfr &) noexcept
37+
{
38+
return nullptr;
39+
}
40+
41+
// types with associated namespace std
42+
struct T_assoc_ns_nr : std::exception
43+
{
44+
};
45+
struct T_assoc_ns_mr : std::exception
46+
{
47+
void *begin() const noexcept { return nullptr; }
48+
void *end() const noexcept { return nullptr; }
49+
};
50+
struct T_assoc_ns_fr : std::exception
51+
{
52+
};
53+
void *begin(const T_assoc_ns_fr &) noexcept
54+
{
55+
return nullptr;
56+
}
57+
void *end(const T_assoc_ns_fr &) noexcept
58+
{
59+
return nullptr;
60+
}
61+
struct T_assoc_ns_mfr : std::exception
62+
{
63+
void *begin() const noexcept { return nullptr; }
64+
void *end() const noexcept { return nullptr; }
65+
};
66+
void *begin(const T_assoc_ns_mfr &) noexcept
67+
{
68+
return nullptr;
69+
}
70+
void *end(const T_assoc_ns_mfr &) noexcept
71+
{
72+
return nullptr;
73+
}
74+
} // namespace test_ns
75+
76+
TEST_CASE("range SFINAE", "[utilities]")
77+
{
78+
CHECK(!zmq::detail::is_range<int>::value);
79+
CHECK(zmq::detail::is_range<std::string>::value);
80+
CHECK(zmq::detail::is_range<std::string &>::value);
81+
CHECK(zmq::detail::is_range<const std::string &>::value);
82+
CHECK(zmq::detail::is_range<decltype("hello")>::value);
83+
CHECK(zmq::detail::is_range<std::initializer_list<int>>::value);
84+
85+
CHECK(!zmq::detail::is_range<test_ns::T_nr>::value);
86+
CHECK(zmq::detail::is_range<test_ns::T_mr>::value);
87+
CHECK(zmq::detail::is_range<test_ns::T_fr>::value);
88+
CHECK(zmq::detail::is_range<test_ns::T_mfr>::value);
89+
90+
CHECK(!zmq::detail::is_range<test_ns::T_assoc_ns_nr>::value);
91+
CHECK(zmq::detail::is_range<test_ns::T_assoc_ns_mr>::value);
92+
CHECK(zmq::detail::is_range<test_ns::T_assoc_ns_fr>::value);
93+
CHECK(zmq::detail::is_range<test_ns::T_assoc_ns_mfr>::value);
94+
}
95+
96+
#endif

zmq.hpp

+57-5
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,55 @@ typedef struct
152152

153153
namespace zmq
154154
{
155+
156+
#ifdef ZMQ_CPP11
157+
namespace detail
158+
{
159+
namespace ranges
160+
{
161+
using std::begin;
162+
using std::end;
163+
template<class T>
164+
auto begin(T&& r) -> decltype(begin(std::forward<T>(r)))
165+
{
166+
return begin(std::forward<T>(r));
167+
}
168+
template<class T>
169+
auto end(T&& r) -> decltype(end(std::forward<T>(r)))
170+
{
171+
return end(std::forward<T>(r));
172+
}
173+
} // namespace ranges
174+
175+
template<class T> using void_t = void;
176+
177+
template<class Iter>
178+
using iter_value_t = typename std::iterator_traits<Iter>::value_type;
179+
180+
template<class Range>
181+
using range_iter_t = decltype(
182+
ranges::begin(std::declval<typename std::remove_reference<Range>::type &>()));
183+
184+
template<class Range>
185+
using range_value_t = iter_value_t<range_iter_t<Range>>;
186+
187+
template<class T, class = void> struct is_range : std::false_type
188+
{
189+
};
190+
191+
template<class T>
192+
struct is_range<
193+
T,
194+
void_t<decltype(
195+
ranges::begin(std::declval<typename std::remove_reference<T>::type &>())
196+
== ranges::end(std::declval<typename std::remove_reference<T>::type &>()))>>
197+
: std::true_type
198+
{
199+
};
200+
201+
} // namespace detail
202+
#endif
203+
155204
typedef zmq_free_fn free_fn;
156205
typedef zmq_pollitem_t pollitem_t;
157206

@@ -278,11 +327,14 @@ class message_t
278327
throw error_t();
279328
}
280329

281-
#if defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11)
282-
// TODO: this function is too greedy, must add
283-
// SFINAE for begin and end support.
284-
template<typename T>
285-
explicit message_t(const T &msg_) : message_t(std::begin(msg_), std::end(msg_))
330+
#ifdef ZMQ_CPP11
331+
template<class Range,
332+
typename = typename std::enable_if<
333+
detail::is_range<Range>::value
334+
&& std::is_trivially_copyable<detail::range_value_t<Range>>::value
335+
&& !std::is_same<Range, message_t>::value>::type>
336+
explicit message_t(const Range &rng) :
337+
message_t(detail::ranges::begin(rng), detail::ranges::end(rng))
286338
{
287339
}
288340
#endif

0 commit comments

Comments
 (0)