message: read: DRY the string specializations

The specializations for std::string, string_wrapper, and
string_path_wrapper are almost identical.  Do some minor
refactoring and DRYing so that the same template specialization
can be used for all 3.

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I7cc3b6e29629f7f11ccd8758176fb9ad4989e624
diff --git a/include/sdbusplus/message/read.hpp b/include/sdbusplus/message/read.hpp
index b30c867..09252ee 100644
--- a/include/sdbusplus/message/read.hpp
+++ b/include/sdbusplus/message/read.hpp
@@ -189,59 +189,28 @@
     }
 };
 
-/** @brief Specialization of read_single for std::strings. */
-template <>
-struct read_single<std::string>
+/** @brief Specialization of read_single for various string class types.
+ *
+ *  Supports std::strings, details::string_wrapper and
+ *  details::string_path_wrapper.
+ */
+template <typename T>
+struct read_single<
+    T, std::enable_if_t<std::is_same_v<T, std::string> ||
+                        std::is_same_v<T, details::string_wrapper> ||
+                        std::is_same_v<T, details::string_path_wrapper>>>
 {
-    template <typename T>
-    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, T&& s)
+    template <typename S>
+    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
     {
-        constexpr auto dbusType = std::get<0>(types::type_id<T>());
+        constexpr auto dbusType = std::get<0>(types::type_id<S>());
         const char* str = nullptr;
         int r = intf->sd_bus_message_read_basic(m, dbusType, &str);
         if (r < 0)
         {
             throw exception::SdBusError(-r, "sd_bus_message_read_basic string");
         }
-        s = str;
-    }
-};
-
-/** @brief Specialization of read_single for details::string_wrapper. */
-template <>
-struct read_single<details::string_wrapper>
-{
-    template <typename S>
-    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
-    {
-        constexpr auto dbusType = std::get<0>(types::type_id<S>());
-        const char* str = nullptr;
-        int r = intf->sd_bus_message_read_basic(m, dbusType, &str);
-        if (r < 0)
-        {
-            throw exception::SdBusError(
-                -r, "sd_bus_message_read_basic string_wrapper");
-        }
-        s.str = str;
-    }
-};
-
-/** @brief Specialization of read_single for details::string_wrapper. */
-template <>
-struct read_single<details::string_path_wrapper>
-{
-    template <typename S>
-    static void op(sdbusplus::SdBusInterface* intf, sd_bus_message* m, S&& s)
-    {
-        constexpr auto dbusType = std::get<0>(types::type_id<S>());
-        const char* str = nullptr;
-        int r = intf->sd_bus_message_read_basic(m, dbusType, &str);
-        if (r < 0)
-        {
-            throw exception::SdBusError(
-                -r, "sd_bus_message_read_basic string_wrapper");
-        }
-        s.str = str;
+        s = T(str);
     }
 };