Skip to content

Commit 09ab208

Browse files
committed
Problem: message_t ctor for ranges too greedy
Solution: Detect ranges with enable_if idiom
1 parent d25c58a commit 09ab208

File tree

3 files changed

+57
-5
lines changed

3 files changed

+57
-5
lines changed

tests/message.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@ static_assert(std::is_nothrow_swappable<zmq::message_t>::value,
1313
"message_t should be nothrow swappable");
1414
#endif
1515

16+
#ifdef ZMQ_CPP11
17+
TEST_CASE("range SFINAE", "[message]")
18+
{
19+
CHECK(!zmq::detail::is_range<int>::value);
20+
CHECK(zmq::detail::is_range<std::string>::value);
21+
CHECK(zmq::detail::is_range<std::string&>::value);
22+
CHECK(zmq::detail::is_range<const std::string&>::value);
23+
CHECK(zmq::detail::is_range<decltype("hello")>::value);
24+
}
25+
#endif
26+
1627
TEST_CASE("message default constructed", "[message]")
1728
{
1829
const zmq::message_t message;
@@ -48,6 +59,12 @@ TEST_CASE("message constructor with iterators", "[message]")
4859
CHECK(0 == memcmp(data, hi_msg.data(), 2));
4960
}
5061

62+
TEST_CASE("message constructor with size", "[message]")
63+
{
64+
const zmq::message_t msg(5);
65+
CHECK(msg.size() == 5);
66+
}
67+
5168
TEST_CASE("message constructor with buffer and size", "[message]")
5269
{
5370
const std::string hi(data);

tests/socket.cpp

Lines changed: 1 addition & 1 deletion
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);

zmq.hpp

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,39 @@ typedef struct
152152

153153
namespace zmq
154154
{
155+
156+
#ifdef ZMQ_CPP11
157+
namespace detail
158+
{
159+
template<class T> using void_t = void;
160+
161+
template<class Iter>
162+
using iter_value_t = typename std::iterator_traits<Iter>::value_type;
163+
164+
template<class Range>
165+
using range_iter_t = decltype(
166+
std::begin(std::declval<typename std::remove_reference<Range>::type &>()));
167+
168+
template<class Range>
169+
using range_value_t = iter_value_t<range_iter_t<Range>>;
170+
171+
template<class T, class = void> struct is_range : std::false_type
172+
{
173+
};
174+
175+
template<class T>
176+
struct is_range<
177+
T,
178+
void_t<decltype(
179+
std::begin(std::declval<typename std::remove_reference<T>::type &>())
180+
== std::end(std::declval<typename std::remove_reference<T>::type &>()))>>
181+
: std::true_type
182+
{
183+
};
184+
185+
} // namespace detail
186+
#endif
187+
155188
typedef zmq_free_fn free_fn;
156189
typedef zmq_pollitem_t pollitem_t;
157190

@@ -278,10 +311,12 @@ class message_t
278311
}
279312

280313
#if defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11)
281-
// TODO: this function is too greedy, must add
282-
// SFINAE for begin and end support.
283-
template<typename T>
284-
explicit message_t(const T &msg_) : message_t(std::begin(msg_), std::end(msg_))
314+
template<class Range,
315+
typename = typename std::enable_if<
316+
detail::is_range<Range>::value
317+
&& std::is_trivially_copyable<detail::range_value_t<Range>>::value
318+
&& !std::is_same<Range, message_t>::value>::type>
319+
explicit message_t(const Range &rng) : message_t(std::begin(rng), std::end(rng))
285320
{
286321
}
287322
#endif

0 commit comments

Comments
 (0)