From be74f60bf51cfaa0bc0fe5ad493e781e15d48d99 Mon Sep 17 00:00:00 2001 From: David Sobek Date: Fri, 24 Apr 2026 08:13:49 -0600 Subject: [PATCH] Allow for vector to string conversions --- include/behaviortree_cpp/basic_types.h | 39 ++++++++++++++++++++++++-- include/behaviortree_cpp/blackboard.h | 11 -------- tests/gtest_ports.cpp | 7 +++++ 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/include/behaviortree_cpp/basic_types.h b/include/behaviortree_cpp/basic_types.h index b61d49c16..5907d846f 100644 --- a/include/behaviortree_cpp/basic_types.h +++ b/include/behaviortree_cpp/basic_types.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -246,6 +247,18 @@ constexpr bool IsConvertibleToString() Expected toJsonString(const Any& value); +// Helper trait to check if templated type is a std::vector +template +struct is_vector : std::false_type +{ +}; + +template +struct is_vector> : std::true_type +{ + using ValueType = T; +}; + /** * @brief toStr is the reverse operation of convertFromString. * @@ -255,10 +268,33 @@ Expected toJsonString(const Any& value); template [[nodiscard]] std::string toStr(const T& value) { + auto throw_unspecialized_error = []() { + throw LogicError(StrCat("Function BT::toStr() not specialized for type [", + BT::demangle(typeid(T)), "]")); + }; + if constexpr(IsConvertibleToString()) { return static_cast(value); } + else if constexpr(is_vector::value) + { + try + { + using InnerType = typename is_vector::ValueType; + std::stringstream ss; + for(auto it = value.begin(); it != --value.end(); ++it) + { + ss << toStr(*it) << ';'; + } + ss << toStr(value.back()); + return ss.str(); + } + catch(LogicError&) + { + throw_unspecialized_error(); + } + } else if constexpr(!std::is_arithmetic_v) { if(auto str = toJsonString(Any(value))) @@ -266,8 +302,7 @@ template return *str; } - throw LogicError(StrCat("Function BT::toStr() not specialized for type [", - BT::demangle(typeid(T)), "]")); + throw_unspecialized_error(); } else { diff --git a/include/behaviortree_cpp/blackboard.h b/include/behaviortree_cpp/blackboard.h index 409ef8a1a..436542bf0 100644 --- a/include/behaviortree_cpp/blackboard.h +++ b/include/behaviortree_cpp/blackboard.h @@ -26,17 +26,6 @@ struct StampedValue Timestamp stamp; }; -// Helper trait to check if templated type is a std::vector -template -struct is_vector : std::false_type -{ -}; - -template -struct is_vector> : std::true_type -{ -}; - // Helper function to check if a demangled type string is a std::vector<..> inline bool isVector(const std::string& type_name) { diff --git a/tests/gtest_ports.cpp b/tests/gtest_ports.cpp index eaaf9733a..cbe644aaf 100644 --- a/tests/gtest_ports.cpp +++ b/tests/gtest_ports.cpp @@ -6,6 +6,13 @@ using namespace BT; +TEST(toStr, ConvertsVectors) +{ + std::string val_str; + ASSERT_NO_THROW(val_str = BT::toStr(std::vector{ 1, 2, 3, 4 })); + EXPECT_EQ(val_str, "1;2;3;4"); +} + class NodeWithPorts : public SyncActionNode { public: