Skip to content

Commit f412ea9

Browse files
committed
Improved range detection supporting ADL
1 parent 2d496cb commit f412ea9

File tree

4 files changed

+119
-16
lines changed

4 files changed

+119
-16
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

-11
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,6 @@ 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-
2716
TEST_CASE("message default constructed", "[message]")
2817
{
2918
const zmq::message_t message;

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

+21-4
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,30 @@ namespace zmq
156156
#ifdef ZMQ_CPP11
157157
namespace detail
158158
{
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+
159175
template<class T> using void_t = void;
160176

161177
template<class Iter>
162178
using iter_value_t = typename std::iterator_traits<Iter>::value_type;
163179

164180
template<class Range>
165181
using range_iter_t = decltype(
166-
std::begin(std::declval<typename std::remove_reference<Range>::type &>()));
182+
ranges::begin(std::declval<typename std::remove_reference<Range>::type &>()));
167183

168184
template<class Range>
169185
using range_value_t = iter_value_t<range_iter_t<Range>>;
@@ -176,8 +192,8 @@ template<class T>
176192
struct is_range<
177193
T,
178194
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 &>()))>>
195+
ranges::begin(std::declval<typename std::remove_reference<T>::type &>())
196+
== ranges::end(std::declval<typename std::remove_reference<T>::type &>()))>>
181197
: std::true_type
182198
{
183199
};
@@ -316,7 +332,8 @@ class message_t
316332
detail::is_range<Range>::value
317333
&& std::is_trivially_copyable<detail::range_value_t<Range>>::value
318334
&& !std::is_same<Range, message_t>::value>::type>
319-
explicit message_t(const Range &rng) : message_t(std::begin(rng), std::end(rng))
335+
explicit message_t(const Range &rng) :
336+
message_t(detail::ranges::begin(rng), detail::ranges::end(rng))
320337
{
321338
}
322339
#endif

0 commit comments

Comments
 (0)