nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
Loading...
Searching...
No Matches
Client< S > Class Template Reference

#include <client.hpp>

Public Types

using ConstSharedPtr = ::rclcpp::ClientHandle<S>
using RequestType = typename S::Request
using ResponseType = typename S::Response
using SharedPtr = ::rclcpp::ClientHandle<S>
using TypedResponseFn = void (*)(const ResponseType& response)
using UniquePtr = ::rclcpp::ClientHandle<S>
 rclcpp::Client<S>::UniquePtr — see SharedPtr.

Public Member Functions

Result async_send_request (const RequestType &req)
 Client ()
 Client (Client &&other)
::rclcpp::QoS get_request_publisher_actual_qos () const
::rclcpp::QoS get_response_subscription_actual_qos () const
const char * get_service_name () const
size_t handle_id () const
 Executor arena slot for the registration; SIZE_MAX until registered.
bool is_valid () const
 Check if the client was registered.
Client & operator= (Client &&other)
::rclcpp::ResultOf< bool > service_is_ready () const
template<typename T = void>
Result wait_for_service ()
Result wait_for_service (uint32_t timeout_ms)
 ~Client ()

Friends

class ::rclcpp::Node

Member Typedef Documentation

◆ ConstSharedPtr

template<typename S>
using Client< S >::ConstSharedPtr = ::rclcpp::ClientHandle<S>

rclcpp::Client<S>::ConstSharedPtr — see SharedPtr. The same handle: async_send_request is const on it (the handle is two words the caller owns; the mutation is the arena's), so there is no mutable/const distinction to draw.

◆ RequestType

template<typename S>
using Client< S >::RequestType = typename S::Request

◆ ResponseType

template<typename S>
using Client< S >::ResponseType = typename S::Response

◆ SharedPtr

template<typename S>
using Client< S >::SharedPtr = ::rclcpp::ClientHandle<S>

rclcpp::Client<S>::SharedPtr — phase-456 W9.

rclcpp::Client<S>::SharedPtr member_; is how ported source declares a client member, so this alias must exist on every target — which std::shared_ptr does not.

IT IS NOT A POINTER TO A Client<S>. A registered client is the arena's; what this names is rclcpp::ClientHandle<S> — two words, copyable, carrying exactly the one verb the census says a dispatch client is asked for. See client_handle.hpp.

◆ TypedResponseFn

template<typename S>
using Client< S >::TypedResponseFn = void (*)(const ResponseType& response)

Phase 189.M3.3.f — typed response-handler signature for the callback-style client (rclcpp async dispatch). The handler runs during spin_once when a reply arrives for a request sent via async_send_request.

phase-456 W3 deleted the TypedResponseFnWithCtx sibling, for the reason stated on Service<S>::TypedServiceFn: the SFINAE guard on Node::create_client admits only a void(*)(const Response&), so no overload could set it and the branch reading it was unreachable.

◆ UniquePtr

template<typename S>
using Client< S >::UniquePtr = ::rclcpp::ClientHandle<S>

Constructor & Destructor Documentation

◆ ~Client()

template<typename S>
Client< S >::~Client ( )
inline

Destructor — there is nothing to release.

The executor arena owns the client, the reply buffer and the handler. This destructor deliberately does not release them: it clears this object's own bookkeeping, and the registration lives until its node is destroyed or a ClientHandle releases it (cli_.reset(), issue 1667). Until phase-456 W9 the same destructor also freed a FUTURE-style client, behind an if (initialized_ && !callback_mode_); that half moved to rclcpp::PollClient<S>, where the condition is unconditional.

◆ Client() [1/2]

template<typename S>
Client< S >::Client ( Client< S > && other)
inline

◆ Client() [2/2]

template<typename S>
Client< S >::Client ( )
inline

Default constructor – creates an unregistered service client. Use Node::create_client() to register one.

Member Function Documentation

◆ async_send_request()

template<typename S>
Result Client< S >::async_send_request ( const RequestType & req)
inline

Phase 189.M3.3.f — THE ONE VERB. Send a request; the reply is delivered to the registered response handler during spin_once (no Future). Returns immediately after sending.

UPSTREAM PARITY: upstream's async_send_request(req) returns a std::shared_future<Response::SharedPtr> and its two-argument form takes a callback per REQUEST. Ours returns a Result and the handler is bound once, at registration — ledgered at cpp:Client::async_send_request, divergence / adopt. What changed in phase-456 W9 is only that the callback_mode_ check is gone with the flag: every rclcpp::Client<S> is a dispatch client now, and the future-style road is rclcpp::PollClient<S>.

◆ get_request_publisher_actual_qos()

template<typename S>
::rclcpp::QoS Client< S >::get_request_publisher_actual_qos ( ) const
inline

The QoS the backend GRANTED this client's REQUEST endpoint — the publisher that sends calls. Issue 1437.

rclcpp::Client::get_request_publisher_actual_qos. ONE create_client builds TWO endpoints that negotiate against DIFFERENT peers, so this and get_response_subscription_actual_qos are two answers and neither stands for the other.

A policy the backend cannot report is an ABSENCE (ReliabilityPolicy::Unknown and friends), never the request echoed back — see Publisher::get_actual_qos.

phase-456 W9 — BOTH HALVES ANSWER, and this accessor is the WORKED EXAMPLE the two later closures copied. Issue 1437 gave a dispatch client executor_ beside handle_id_, and nros_cpp_service_client_get_actual_qos serves both roads by construction — storage for the owner, (executor, handle_id) for the arena — so the upstream no-argument spelling was reachable here with no weakening and no ledger row was ever owed.

W9 had to leave get_actual_qos off the dispatch Subscription<M> for want of exactly that: the type held only sched_handle_id_. Both ends of that gap are closed now, each by taking this shape rather than by changing a signature — the subscription carries its executor since phase-467 (2026-09-25, its ledger row deleted), and this class's own service_is_ready / wait_for_service since 2026-09-28.

◆ get_response_subscription_actual_qos()

template<typename S>
::rclcpp::QoS Client< S >::get_response_subscription_actual_qos ( ) const
inline

The QoS the backend GRANTED this client's RESPONSE endpoint — the subscription that receives replies. Issue 1437; see get_request_publisher_actual_qos.

◆ get_service_name()

template<typename S>
const char * Client< S >::get_service_name ( ) const
inline

Read back the service name this client was created on — phase-444.

rclcpp's ClientBase::get_service_name, and the client half of "four entity families, one accessor" (ledger rows cpp:Client::get_service_name and cpp:Service::get_service_name): Publisher and Subscription have had get_topic_name() all along, both action tiers gained get_action_name() in phase-417 W4.b, and the service pair was the one family with no accessor in any C++ tier.

The name lives C++-side in service_name_, for the reason ActionServer::get_action_name states: the runtime does NOT own it. nros_cpp_service_client_register takes service_name and drops it, so there is nothing FFI-side to hand back, and a borrowed const char* was rejected because create_client takes a pointer a hosted caller may well have obtained from a temporary.

Returns "" (never NULL) on an unregistered client, matching Publisher::get_topic_name and both action tiers.

phase-456 W9 split this class in two and the method answers on BOTH halves, unchanged — the same shape Service::get_service_name took under W5. Each half keeps its own service_name_, because the copy is made at create from the argument the caller passed and neither owner can recover it afterwards.

◆ handle_id()

template<typename S>
size_t Client< S >::handle_id ( ) const
inline

Executor arena slot for the registration; SIZE_MAX until registered.

◆ is_valid()

template<typename S>
bool Client< S >::is_valid ( ) const
inline

Check if the client was registered.

◆ operator=()

template<typename S>
Client & Client< S >::operator= ( Client< S > && other)
inline

◆ service_is_ready()

template<typename S>
::rclcpp::ResultOf< bool > Client< S >::service_is_ready ( ) const
inline

Is a matching service server visible? — rclcpp::ClientBase:: service_is_ready, no arguments, as upstream's is.

  • ok(true) — at least one matching server is currently visible.
  • ok(false) — none discovered yet.
  • error(Unsupported) — the backend cannot answer (XRCE has no participant enumeration); fall back to a timed wait_for_service or assume reachability.
  • error(<code>) — the probe itself failed.

Never spins the executor, so it is safe inside a callback. The tri-state is the divergence from upstream's bare bool and is ledgered at cpp:Client::service_is_ready: RFC-0018 forbids exceptions, so a failed probe and a successful "no" must be distinguishable by return value.

This is the gap phase-456 W9 RECORDED, closed 2026-09-28. The split left this verb on the future-style half alone, because nros_cpp_service_client_server_available read the RmwServiceClient in CALLER storage and a dispatch client has none — so a porter holding a Client<S>::SharedPtr could not ask at all. The fix is the FFI's, not the signature's: that entry point now takes (storage, executor, handle_id), the shape nros_cpp_service_client_get_actual_qos has had since issue 1437, and this class already holds {executor_, handle_id_}. Inventing an Executor& parameter here was refused — a method that exists to adopt the upstream spelling cannot close a gap by leaving it.

◆ wait_for_service() [1/2]

template<typename S>
template<typename T = void>
Result Client< S >::wait_for_service ( )
inline

REFUSED — wait_for_service() with no budget. phase-417 stage 3.

A member template rather than = delete for the C++14 reason given on Executor::spin_once(): a deleted function carries no message.

◆ wait_for_service() [2/2]

template<typename S>
Result Client< S >::wait_for_service ( uint32_t timeout_ms)
inline

Block until a matching service server is discoverable — rclcpp::ClientBase::wait_for_service.

Spins the executor cooperatively while probing, so do NOT call it from inside a callback; use service_is_ready there. Returns ok when the server is visible, Timeout when the budget elapses, Unsupported at once when the backend cannot know (XRCE — issue 1686; a caller that may send blind proceeds).

The budget is REQUIRED — phase-417 stage 3, and the reason is RFC-0021 rather than convenience: this call drives a single-threaded executor, so a wait that never returns starves every other entity, and uint32_t has no value to port upstream's -1 to. The no-argument form is a compile error carrying NROS_RCLCPP_REFUSE_UNBOUNDED_WAIT, exactly as it is on rclcpp::PollClient<S> and rclcpp_action::Client<A> — one concept, now three sites, each with its own expected-failure TU.

Closed 2026-09-28 with service_is_ready; that method's note carries why the remedy was the FFI's argument list and not this one.

◆ ::rclcpp::Node

template<typename S>
friend class ::rclcpp::Node
friend

The documentation for this class was generated from the following file: