@@ -454,6 +454,18 @@ Timer::SharedPtr create_timer(
454454namespace autoware ::agnocast_wrapper
455455{
456456
457+ // Service-callback traits (mirror of the Agnocast-build definitions; defined per-build because they
458+ // depend on the AUTOWARE_SERVER_*_PTR macros, which differ between builds).
459+ template <typename Func, typename ServiceT>
460+ inline constexpr bool is_message_ptr_service_callback_v = std::is_invocable_v<
461+ std::decay_t <Func>, AUTOWARE_SERVER_REQUEST_PTR (ServiceT) &&,
462+ AUTOWARE_SERVER_RESPONSE_PTR (ServiceT) &&>;
463+
464+ template <typename Func, typename ServiceT>
465+ inline constexpr bool is_shared_ptr_service_callback_v = std::is_invocable_v<
466+ std::decay_t <Func>, std::shared_ptr<typename ServiceT::Request> &,
467+ std::shared_ptr<typename ServiceT::Response> &>;
468+
457469// / @brief Node class for the non-Agnocast build.
458470// /
459471// / Owns an internal rclcpp::Node and forwards a curated set of members to it; it does NOT derive
@@ -713,7 +725,14 @@ class Node
713725 }
714726
715727 // ===== Service (rclcpp::QoS overload; same rationale as create_client) =====
716- template <typename ServiceT, typename Func>
728+ // Constrained to the same callback set as the Agnocast build, so the rclcpp-only forms
729+ // (with-request-header / defer-response) are rejected here instead of silently accepted.
730+ template <
731+ typename ServiceT, typename Func,
732+ std::enable_if_t <
733+ is_message_ptr_service_callback_v<Func, ServiceT> ||
734+ is_shared_ptr_service_callback_v<Func, ServiceT>,
735+ int > = 0 >
717736 typename rclcpp::Service<ServiceT>::SharedPtr create_service (
718737 const std::string & service_name, Func && callback,
719738 const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
@@ -727,6 +746,27 @@ class Node
727746#endif
728747 }
729748
749+ // Fallback overload: neither callback form matched. Exists only to turn the otherwise opaque
750+ // "no matching function" error into the static_assert message below (mirrors the Agnocast build).
751+ template <
752+ typename ServiceT, typename Func,
753+ std::enable_if_t <
754+ !is_message_ptr_service_callback_v<Func, ServiceT> &&
755+ !is_shared_ptr_service_callback_v<Func, ServiceT>,
756+ int > = 0 >
757+ typename rclcpp::Service<ServiceT>::SharedPtr create_service (
758+ const std::string & service_name, Func && callback,
759+ const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
760+ rclcpp::CallbackGroup::SharedPtr group = nullptr)
761+ {
762+ static_assert (
763+ is_message_ptr_service_callback_v<Func, ServiceT> ||
764+ is_shared_ptr_service_callback_v<Func, ServiceT>,
765+ " Service callback must be invocable with "
766+ " (AUTOWARE_SERVER_REQUEST_PTR(ServiceT), AUTOWARE_SERVER_RESPONSE_PTR(ServiceT)) or with "
767+ " (std::shared_ptr<ServiceT::Request>, std::shared_ptr<ServiceT::Response>)." );
768+ }
769+
730770 // ===== Timer =====
731771 template <typename DurationRepT = int64_t , typename DurationT = std::milli, typename CallbackT>
732772 rclcpp::TimerBase::SharedPtr create_wall_timer (
0 commit comments