str/cat: Simplify append logic

Change-Id: I1719fc5cf545d8d5ed5bfc82c32552f22bdfa432
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/include/stdplus/str/cat.hpp b/include/stdplus/str/cat.hpp
index fc97b17..6ce7ee3 100644
--- a/include/stdplus/str/cat.hpp
+++ b/include/stdplus/str/cat.hpp
@@ -8,32 +8,29 @@
 namespace detail
 {
 
-template <typename CharT, typename Traits, typename Alloc, typename... Views>
-constexpr void strAppendViews(std::basic_string<CharT, Traits, Alloc>& dst,
-                              Views... views)
+template <typename CharT, typename Traits, typename Alloc, typename... CharTs>
+constexpr void strAppend(std::basic_string<CharT, Traits, Alloc>& dst,
+                         std::basic_string_view<CharTs>... strs)
 {
-    dst.reserve((dst.size() + ... + views.size()));
-    (dst.append(views), ...);
+    dst.reserve((dst.size() + ... + strs.size()));
+    (dst.append(strs), ...);
 }
 
-template <typename CharT,
-          typename Traits = std::basic_string_view<CharT>::traits_type>
-struct DedSV : std::basic_string_view<CharT, Traits>
+template <typename CharT>
+struct DedSV : std::basic_string_view<CharT>
 {
-    template <typename... Args>
-    constexpr DedSV(Args&&... args) :
-        std::basic_string_view<CharT, Traits>(std::forward<Args>(args)...)
+    DedSV(const CharT* p) noexcept : std::basic_string_view<CharT>(p) {}
+    template <typename Traits, typename Alloc>
+    DedSV(const std::basic_string<CharT, Traits, Alloc>& s) noexcept :
+        std::basic_string_view<CharT>(s)
+    {}
+    DedSV(std::basic_string_view<CharT> sv) noexcept :
+        std::basic_string_view<CharT>(sv)
     {}
 };
 
-template <typename CharT>
-DedSV(const CharT*) -> DedSV<CharT>;
-
-template <typename CharT, typename Traits, typename Alloc>
-DedSV(const std::basic_string<CharT, Traits, Alloc>&) -> DedSV<CharT, Traits>;
-
-template <typename CharT, typename Traits>
-DedSV(std::basic_string_view<CharT, Traits>) -> DedSV<CharT, Traits>;
+DedSV(const auto& C)
+    -> DedSV<std::decay_t<std::remove_pointer_t<decltype(std::data(C))>>>;
 
 } // namespace detail
 
@@ -46,11 +43,9 @@
  *  @param[in, out] dst - The string being appended to
  *  @param[in] ...strs  - An arbitrary number of strings to concatenate
  */
-template <typename CharT, typename Traits, typename Alloc, typename... Strs>
-constexpr void strAppend(std::basic_string<CharT, Traits, Alloc>& dst,
-                         const Strs&... strs)
+constexpr void strAppend(auto& dst, const auto&... strs)
 {
-    detail::strAppendViews(dst, detail::DedSV(strs)...);
+    detail::strAppend(dst, detail::DedSV(strs)...);
 }
 
 /** @brief Concatenates multiple strings together in the most optimal
@@ -61,19 +56,18 @@
  */
 template <typename CharT = char,
           typename Traits = std::basic_string<CharT>::traits_type,
-          typename Alloc = std::basic_string<CharT>::allocator_type,
-          typename... Strs>
-constexpr std::basic_string<CharT, Traits, Alloc> strCat(const Strs&... strs)
+          typename Alloc = std::basic_string<CharT>::allocator_type>
+constexpr auto strCat(const auto&... strs)
 {
     std::basic_string<CharT, Traits, Alloc> ret;
     strAppend(ret, strs...);
     return ret;
 }
-template <typename CharT, typename Traits, typename Alloc, typename... Strs>
-constexpr std::basic_string<CharT, Traits, Alloc>
-    strCat(std::basic_string<CharT, Traits, Alloc>&& in, const Strs&... strs)
+template <typename CharT, typename Traits, typename Alloc>
+constexpr auto strCat(std::basic_string<CharT, Traits, Alloc>&& in,
+                      const auto&... strs)
 {
-    std::basic_string<CharT, Traits, Alloc> ret = std::move(in);
+    auto ret = std::move(in);
     strAppend(ret, strs...);
     return ret;
 }
diff --git a/test/str/cat.cpp b/test/str/cat.cpp
index 758facc..ef958ea 100644
--- a/test/str/cat.cpp
+++ b/test/str/cat.cpp
@@ -1,4 +1,5 @@
 #include <stdplus/str/cat.hpp>
+#include <stdplus/zstring_view.hpp>
 
 #include <string>
 #include <string_view>
@@ -23,7 +24,8 @@
 
 TEST(StrCat, Multi)
 {
-    EXPECT_EQ("func world test", strCat("func", " world"sv, " test"s));
+    EXPECT_EQ("func world test ff",
+              strCat("func", " world"sv, " test"s, " ff"_zsv));
 }
 
 TEST(StrCat, MoveStr)