Skip to content

Improve constexpr coverage in zmq.hpp with C++11/14/17 compatibility#684

Open
mberk-yilmaz wants to merge 6 commits intozeromq:masterfrom
mberk-yilmaz:master
Open

Improve constexpr coverage in zmq.hpp with C++11/14/17 compatibility#684
mberk-yilmaz wants to merge 6 commits intozeromq:masterfrom
mberk-yilmaz:master

Conversation

@mberk-yilmaz
Copy link
Copy Markdown
Contributor

What changed

This PR expands constexpr usage in zmq.hpp with a compatibility-first approach across C++11/14/17.

zmq.hpp

  • Define ZMQ_EXTENDED_CONSTEXPR as constexpr (under existing compiler/version guards).
  • Add/extend constexpr on safe pointer-state observers:
    • context_t::operator bool() const
    • detail::socket_base::handle() const
    • detail::socket_base::operator bool() const
    • detail::socket_base::connected() const
  • Keep non-const observer forms conditionally constexpr only when ZMQ_EXTENDED_CONSTEXPR is available.
  • Make socket_ref null-comparison operators constexpr.
  • Make detail::socket_base operator==/operator!= constexpr and use direct pointer equality.
  • Add constexpr-friendly updates for trivial value wrappers:
    • recv_buffer_size::truncated()
    • detail::trivial_optional<T> value constructor, operator bool(), has_value().

Tests

  • Strengthen compile-time coverage with static_assert:
    • tests/socket.cpp: socket_base constexpr handle/bool checks
    • tests/socket_ref.cpp: constexpr null comparison checks
    • tests/context.cpp: constexpr checks for recv_buffer_size::truncated() and fallback trivial_optional (!CPPZMQ_HAS_OPTIONAL)

Why this is safe

  • No runtime ZMQ call paths were made constexpr; changes are limited to trivial observers/value-state helpers.
  • Existing compiler guards are preserved; extended constexpr remains opt-in by language/compiler capability.
  • No ABI-impacting layout changes.
  • Null/pointer semantics are unchanged (only compile-time evaluability improved).
  • Potentially risky areas (buffer pointer arithmetic, pointer ordering operators) were intentionally left unchanged for portability/semantic safety.

Compatibility notes

  • C++11: baseline support preserved.
  • C++14/17: additional constexpr opportunities activate via existing guard logic.
  • Legacy compiler constraints already encoded in ZMQ_EXTENDED_CONSTEXPR remain respected.

Validation

Validated by building and testing in three standards:

  • C++11: build + full unit tests pass
  • C++14: build + full unit tests pass
  • C++17: build + full unit tests pass

mberk-yilmaz and others added 6 commits March 18, 2026 12:48
Add const-qualified overloads for multipart_t::front() and back() in `zmq_addon.hpp`.

Note on API shape:
- In a container-style API, non-const overloads would typically return `message_t&`.
- This change intentionally preserves existing non-const return types (`const message_t&`)
  for backward-compatibility and to avoid broadening mutability semantics in this PR.

Also extend `tests/multipart.cpp` with compile-time and runtime checks for const/non-const access paths.

No behavioral change intended.
- map ZMQ_EXTENDED_CONSTEXPR to constexpr under existing compiler guards
- add constexpr to safe state observers in context_t/socket_base/socket_ref paths
- add constexpr to recv_buffer_size::truncated and fallback trivial_optional observers/ctor
- strengthen compile-time tests with static_assert checks in context/socket/socket_ref tests
- keep risky/non-portable areas (buffer pointer arithmetic, pointer ordering semantics) unchanged
@coveralls
Copy link
Copy Markdown

Pull Request Test Coverage Report for Build 23609355763

Details

  • 27 of 28 (96.43%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.08%) to 87.996%

Changes Missing Coverage Covered Lines Changed/Added Lines %
zmq.hpp 27 28 96.43%
Totals Coverage Status
Change from base Build 23429037824: 0.08%
Covered Lines: 953
Relevant Lines: 1083

💛 - Coveralls

@gummif
Copy link
Copy Markdown
Member

gummif commented Mar 27, 2026

Why these two ways of marking functions constexpr?

// why not just use ZMQ_CONSTEXPR_FN?
// or if there is need why not just ZMQ_EXTENDED_CONSTEXPR operator void *() ZMQ_NOTHROW { return _handle; }
#ifdef ZMQ_EXTENDED_CONSTEXPR
    ZMQ_EXTENDED_CONSTEXPR operator void *() ZMQ_NOTHROW { return _handle; }
#else
    operator void *() ZMQ_NOTHROW { return _handle; }
#endif

    ZMQ_CONSTEXPR_FN operator void const *() const ZMQ_NOTHROW { return _handle; }

Related to this it's interesting to still support C++98 with C++26 releasing this year.

@@ -965,7 +986,10 @@ template<class T> class trivial_optional
using value_type = T;

trivial_optional() = default;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ZMQ_CONSTEXPR_FN also?

inline ZMQ_CONSTEXPR_FN bool operator==(const detail::socket_base &a,
const detail::socket_base &b) ZMQ_NOTHROW
{
return std::equal_to<const void *>()(a.handle(), b.handle());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep this to avoid UB

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants