diff --git a/tests/message.cpp b/tests/message.cpp index aef0ae5..17fb088 100644 --- a/tests/message.cpp +++ b/tests/message.cpp @@ -70,13 +70,40 @@ TEST_CASE("message constructor with char array", "[message]") CHECK(0 == memcmp(data, hi_msg.data(), 2)); } -#if defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) -TEST_CASE("message constructor with container", "[message]") +#if defined(ZMQ_CPP11) && !defined(ZMQ_CPP11_PARTIAL) +TEST_CASE("message constructor with container - deprecated", "[message]") { - const std::string hi(data); - zmq::message_t hi_msg(hi); - CHECK(2u == hi_msg.size()); - CHECK(0 == memcmp(data, hi_msg.data(), 2)); + zmq::message_t hi_msg("Hi"); // deprecated + REQUIRE(3u == hi_msg.size()); + CHECK(0 == memcmp(data, hi_msg.data(), 3)); +} + +TEST_CASE("message constructor with container of trivial data", "[message]") +{ + int buf[3] = {1, 2, 3}; + zmq::message_t msg(buf); + REQUIRE(sizeof(buf) == msg.size()); + CHECK(0 == memcmp(buf, msg.data(), msg.size())); +} + +TEST_CASE("message constructor with strings", "[message]") +{ + SECTION("string") + { + const std::string hi(data); + zmq::message_t hi_msg(hi); + CHECK(2u == hi_msg.size()); + CHECK(0 == memcmp(data, hi_msg.data(), 2)); + } +#if CPPZMQ_HAS_STRING_VIEW + SECTION("string_view") + { + const std::string_view hi(data); + zmq::message_t hi_msg(hi); + CHECK(2u == hi_msg.size()); + CHECK(0 == memcmp(data, hi_msg.data(), 2)); + } +#endif } #endif @@ -162,6 +189,12 @@ TEST_CASE("message to string", "[message]") CHECK(a.to_string_view() == ""); CHECK(b.to_string_view() == "Foo"); #endif + +#if defined(ZMQ_CPP11) && !defined(ZMQ_CPP11_PARTIAL) + const zmq::message_t depr("Foo"); // deprecated + CHECK(depr.to_string() != "Foo"); + CHECK(depr.to_string() == std::string("Foo", 4)); +#endif } #if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0) diff --git a/zmq.hpp b/zmq.hpp index 5aa6845..9135c01 100644 --- a/zmq.hpp +++ b/zmq.hpp @@ -342,8 +342,8 @@ inline int poll(std::vector &items, long timeout_ = -1) } template -inline int poll(std::array& items, - std::chrono::milliseconds timeout) +inline int poll(std::array &items, + std::chrono::milliseconds timeout) { return poll(items.data(), items.size(), static_cast(timeout.count())); } @@ -362,6 +362,20 @@ inline std::tuple version() zmq_version(&std::get<0>(v), &std::get<1>(v), &std::get<2>(v)); return v; } + +#if !defined(ZMQ_CPP11_PARTIAL) +namespace detail +{ +template struct is_char_type +{ + // true if character type for string literals in C++11 + static constexpr bool value = + std::is_same::value || std::is_same::value + || std::is_same::value || std::is_same::value; +}; +} +#endif + #endif class message_t @@ -398,8 +412,7 @@ class message_t int rc = zmq_msg_init_size(&msg, size_); if (rc != 0) throw error_t(); - if (size_) - { + if (size_) { // this constructor allows (nullptr, 0), // memcpy with a null pointer is UB memcpy(data(), data_, size_); @@ -413,16 +426,40 @@ class message_t throw error_t(); } + // overload set of string-like types and generic containers #if defined(ZMQ_CPP11) && !defined(ZMQ_CPP11_PARTIAL) + // NOTE this constructor will include the null terminator + // when called with a string literal. + // An overload taking const char* can not be added because + // it would be preferred over this function and break compatiblity. + template< + class Char, + size_t N, + typename = typename std::enable_if::value>::type> + ZMQ_DEPRECATED("from 4.7.0, use constructors taking iterators, (pointer, size) " + "or strings instead") + explicit message_t(const Char (&data)[N]) : + message_t(detail::ranges::begin(data), detail::ranges::end(data)) + { + } + template::value && ZMQ_IS_TRIVIALLY_COPYABLE(detail::range_value_t) + && !detail::is_char_type>::value && !std::is_same::value>::type> explicit message_t(const Range &rng) : message_t(detail::ranges::begin(rng), detail::ranges::end(rng)) { } + + explicit message_t(const std::string &str) : message_t(str.data(), str.size()) {} + +#if CPPZMQ_HAS_STRING_VIEW + explicit message_t(std::string_view str) : message_t(str.data(), str.size()) {} +#endif + #endif #ifdef ZMQ_HAS_RVALUE_REFS @@ -1337,19 +1374,19 @@ template struct array_option #define ZMQ_DEFINE_INTEGRAL_OPT(OPT, NAME, TYPE) \ using NAME##_t = integral_option; \ - ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME{} + ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} #define ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(OPT, NAME, TYPE) \ using NAME##_t = integral_option; \ - ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME{} + ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} #define ZMQ_DEFINE_ARRAY_OPT(OPT, NAME) \ using NAME##_t = array_option; \ - ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME{} + ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} #define ZMQ_DEFINE_ARRAY_OPT_BINARY(OPT, NAME) \ using NAME##_t = array_option; \ - ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME{} + ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} #define ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(OPT, NAME) \ using NAME##_t = array_option; \ - ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME{} + ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} // duplicate definition from libzmq 4.3.3 #if defined _WIN32 @@ -2161,7 +2198,6 @@ class socket_t : public detail::socket_base throw error_t(); if (ctxptr == ZMQ_NULLPTR) throw error_t(); - } };