diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 59c20a99..5c91ac4a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -25,7 +25,8 @@ add_executable( poller.cpp active_poller.cpp multipart.cpp - monitor.cpp + monitor.cpp + utilities.cpp ) add_dependencies(unit_tests catch) diff --git a/tests/message.cpp b/tests/message.cpp index 15f0484a..d8721073 100644 --- a/tests/message.cpp +++ b/tests/message.cpp @@ -48,6 +48,12 @@ TEST_CASE("message constructor with iterators", "[message]") CHECK(0 == memcmp(data, hi_msg.data(), 2)); } +TEST_CASE("message constructor with size", "[message]") +{ + const zmq::message_t msg(5); + CHECK(msg.size() == 5); +} + TEST_CASE("message constructor with buffer and size", "[message]") { const std::string hi(data); diff --git a/tests/socket.cpp b/tests/socket.cpp index 7eab2bd3..b4236b23 100644 --- a/tests/socket.cpp +++ b/tests/socket.cpp @@ -184,7 +184,7 @@ TEST_CASE("socket send recv message_t", "[socket]") s2.bind("inproc://test"); s.connect("inproc://test"); - zmq::message_t smsg(size_t{10}); + zmq::message_t smsg(10); const auto res_send = s2.send(smsg, zmq::send_flags::none); CHECK(res_send); CHECK(*res_send == 10); diff --git a/tests/utilities.cpp b/tests/utilities.cpp new file mode 100644 index 00000000..c7b8c998 --- /dev/null +++ b/tests/utilities.cpp @@ -0,0 +1,96 @@ +#include +#include + +#ifdef ZMQ_CPP11 + +namespace test_ns +{ +struct T_nr +{ +}; +struct T_mr +{ + void *begin() const noexcept { return nullptr; } + void *end() const noexcept { return nullptr; } +}; +struct T_fr +{ +}; +void *begin(const T_fr &) noexcept +{ + return nullptr; +} +void *end(const T_fr &) noexcept +{ + return nullptr; +} +struct T_mfr +{ + void *begin() const noexcept { return nullptr; } + void *end() const noexcept { return nullptr; } +}; +void *begin(const T_mfr &) noexcept +{ + return nullptr; +} +void *end(const T_mfr &) noexcept +{ + return nullptr; +} + +// types with associated namespace std +struct T_assoc_ns_nr : std::exception +{ +}; +struct T_assoc_ns_mr : std::exception +{ + void *begin() const noexcept { return nullptr; } + void *end() const noexcept { return nullptr; } +}; +struct T_assoc_ns_fr : std::exception +{ +}; +void *begin(const T_assoc_ns_fr &) noexcept +{ + return nullptr; +} +void *end(const T_assoc_ns_fr &) noexcept +{ + return nullptr; +} +struct T_assoc_ns_mfr : std::exception +{ + void *begin() const noexcept { return nullptr; } + void *end() const noexcept { return nullptr; } +}; +void *begin(const T_assoc_ns_mfr &) noexcept +{ + return nullptr; +} +void *end(const T_assoc_ns_mfr &) noexcept +{ + return nullptr; +} +} // namespace test_ns + +TEST_CASE("range SFINAE", "[utilities]") +{ + CHECK(!zmq::detail::is_range::value); + CHECK(zmq::detail::is_range::value); + CHECK(zmq::detail::is_range::value); + CHECK(zmq::detail::is_range::value); + CHECK(zmq::detail::is_range::value); + CHECK(zmq::detail::is_range>::value); + + CHECK(!zmq::detail::is_range::value); + CHECK(zmq::detail::is_range::value); + CHECK(zmq::detail::is_range::value); + CHECK(zmq::detail::is_range::value); + + CHECK(!zmq::detail::is_range::value); + CHECK(zmq::detail::is_range::value); + CHECK(zmq::detail::is_range::value); + CHECK(zmq::detail::is_range::value); +} + +#endif diff --git a/zmq.hpp b/zmq.hpp index eb8e9cb8..e336b1b1 100644 --- a/zmq.hpp +++ b/zmq.hpp @@ -152,6 +152,55 @@ typedef struct namespace zmq { + +#ifdef ZMQ_CPP11 +namespace detail +{ +namespace ranges +{ +using std::begin; +using std::end; +template +auto begin(T&& r) -> decltype(begin(std::forward(r))) +{ + return begin(std::forward(r)); +} +template +auto end(T&& r) -> decltype(end(std::forward(r))) +{ + return end(std::forward(r)); +} +} // namespace ranges + +template using void_t = void; + +template +using iter_value_t = typename std::iterator_traits::value_type; + +template +using range_iter_t = decltype( + ranges::begin(std::declval::type &>())); + +template +using range_value_t = iter_value_t>; + +template struct is_range : std::false_type +{ +}; + +template +struct is_range< + T, + void_t::type &>()) + == ranges::end(std::declval::type &>()))>> + : std::true_type +{ +}; + +} // namespace detail +#endif + typedef zmq_free_fn free_fn; typedef zmq_pollitem_t pollitem_t; @@ -278,11 +327,14 @@ class message_t throw error_t(); } -#if defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) - // TODO: this function is too greedy, must add - // SFINAE for begin and end support. - template - explicit message_t(const T &msg_) : message_t(std::begin(msg_), std::end(msg_)) +#ifdef ZMQ_CPP11 + template::value + && std::is_trivially_copyable>::value + && !std::is_same::value>::type> + explicit message_t(const Range &rng) : + message_t(detail::ranges::begin(rng), detail::ranges::end(rng)) { } #endif