3232#define TF2__IMPL__CONVERT_H_
3333
3434#include < geometry_msgs/msg/quaternion.hpp>
35+ #include < std_msgs/msg/header.hpp>
3536
3637#include " ../time.h"
3738#include " forward.h"
3839
40+ #include < type_traits>
41+
42+
3943namespace tf2
4044{
4145namespace impl
4246{
47+
48+ // / Helper to always trigger \c static_assert s
49+ template <typename T>
50+ constexpr bool alwaysFalse = false ;
51+
52+ /* * \brief Check whether a message is stamped and has a std_msgs::msg::Header member.
53+ *
54+ * It will be indicated with the static member valiable \c value .
55+ * \tparam Message The message to check
56+ */
57+ template <typename Message, typename = int >
58+ struct MessageHasStdHeader : std::false_type {};
59+
60+ /* * \brief Check whether a message is stamped and has a std_msgs::msg::Header member.
61+ *
62+ * It will be indicated with the static member valiable \c value .
63+ * \tparam Message The message to check
64+ */
65+ template <typename Message>
66+ class MessageHasStdHeader <Message, decltype (&Message::header, 0 )>
67+ {
68+ template <typename Alloc>
69+ static std::true_type headerIsStdHeader (std_msgs::msg::Header_<Alloc>);
70+ template <typename = void >
71+ static std::false_type headerIsStdHeader (...);
72+
73+ public:
74+ // / true if Message has a member \c header of type std_msgs::msg::Header.
75+ static constexpr bool value = decltype (headerIsStdHeader(std::declval<Message>().header))::value;
76+ };
77+
4378/* *
4479 * \brief Mapping between Datatypes (like \c Vector3d ) and their default ROS Message types.
4580 *
@@ -52,6 +87,9 @@ namespace impl
5287template <class Datatype , class >
5388struct DefaultMessageForDatatype
5489{
90+ static_assert (
91+ alwaysFalse<Datatype>, " No default message type defined, "
92+ " please check your header file includes!" );
5593 // using type = ...;
5694};
5795
@@ -73,6 +111,9 @@ struct DefaultMessageForDatatype
73111template <class Datatype , class >
74112struct DefaultTransformType
75113{
114+ static_assert (
115+ alwaysFalse<Datatype>, " No default transform type defined, "
116+ " please check your header file includes!" );
76117 // using type = ...;
77118};
78119
@@ -100,6 +141,9 @@ struct DefaultTransformType
100141template <class Datatype , class Message , class >
101142struct ConversionImplementation
102143{
144+ static_assert (
145+ alwaysFalse<Datatype>, " No Conversion Implementation available, "
146+ " please check your header file includes!" );
103147 // void toMsg(const Datatype&, Message&);
104148 // void fromMsg(const Message&, Datatype&);
105149};
@@ -140,6 +184,9 @@ struct ConversionImplementation
140184template <class StampedMessage >
141185struct StampedMessageTraits
142186{
187+ static_assert (
188+ alwaysFalse<StampedMessage>, " No traits for this stamped message type available, "
189+ " please check your header file includes!" );
143190 // using UntampedType = ...;
144191 // static UntampedType& accessMessage(StampedMsg &);
145192 // static UntampedType getMessage(StampedMsg const&);
@@ -172,6 +219,9 @@ struct StampedMessageTraits
172219template <class UnstampedMessage >
173220struct UnstampedMessageTraits
174221{
222+ static_assert (
223+ alwaysFalse<UnstampedMessage>, " No traits for this message type available, "
224+ " please check your header file includes!" );
175225 // using StampedType = ...;
176226 // using StampedTypeWithCovariance = ...;
177227};
@@ -364,41 +414,36 @@ inline void Converter<false, false>::convert(const A & a, B & b)
364414 fromMsg<>(toMsg<>(a), b);
365415}
366416
367- template <typename T>
368- using void_t = void ;
369-
370417/* *
371418 * \brief Default implementation for extracting timestamps and frame IDs.
372419 *
373420 * Both static member functions are for stamped ROS messages.
374- * They are SFINAE'd out if T is not a stamped ROS message.
375421 *
376422 * \tparam T Arbitrary datatype
377423 */
378424template <typename T, int >
379425struct StampedAttributesHelper
380426{
427+ static_assert (
428+ MessageHasStdHeader<T>::value,
429+ " Trying to use default implementation for stamped message, "
430+ " but the datatype does not have a Header member." );
431+
381432 /* *\brief Get the timestamp from data
382- * \param t The data input.
433+ * \param[in] t The data input.
383434 * \return The timestamp associated with the data.
384- *
385- * The second parameter is needed to hide the default implementation if T is not a stamped ROS message.
386435 */
387- static tf2::TimePoint getTimestamp (
388- const T & t, void_t <typename StampedMessageTraits<T>::UntampedType> * = nullptr )
436+ static tf2::TimePoint getTimestamp (const T & t)
389437 {
390438 tf2::TimePoint timestamp;
391439 tf2::fromMsg<>(t.header .stamp , timestamp);
392440 return timestamp;
393441 }
394442 /* *\brief Get the frame_id from data
395- * \param t The data input.
443+ * \param[in] t The data input.
396444 * \return The frame_id associated with the data.
397- *
398- * The second parameter is needed to hide the default implementation if T is not a stamped ROS message.
399445 */
400- static std::string getFrameId (
401- const T & t, void_t <typename StampedMessageTraits<T>::UntampedType> * = nullptr )
446+ static std::string getFrameId (const T & t)
402447 {
403448 return t.header .frame_id ;
404449 }
0 commit comments