M
M
Mercury132022-03-27 15:54:37
C++ / C#
Mercury13, 2022-03-27 15:54:37

How to make template function accept const char*?

namespace str {
    /// @brief remainderSv
    ///         remainderSv("string", "st") = "ring"
    template <class C, class T = std::char_traits<C>>
    std::basic_string_view<C,T> remainderSv(
            std::basic_string_view<C,T> s,
            std::basic_string_view<C,T> prefix)
    {
        if (s.length() <= prefix.length()
                || !s.starts_with(prefix))
            return {};
        return s.substr(prefix.length(), s.length() - prefix.length());
    }
}  // namespace str

// Тест, сделанный системой Google test
TEST (RemainderSv, Pref)
{
    std::string_view s = "string";
    EXPECT_EQ("ing", str::remainderSv(s, "str"));
}

How to make the code compile? Otherwise, it does not yet allow both string_view/const char* and string_view/string.
If you add a non-template function, everything works, but why?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
M
Mercury13, 2022-03-27
@Mercury13

template <class T> struct string_traits;

    template <class C, class T, class A>
    struct string_traits<std::basic_string<C,T,A>> {
        using Ch = C;
        using Tr = T;
        using Sv = std::basic_string_view<C,T>;
    };

    template <class C, class T>
    struct string_traits<std::basic_string_view<C,T>> {
        using Ch = C;
        using Tr = T;
        using Sv = std::basic_string_view<C,T>;
    };

    template <class C>
    struct string_traits<const C*> {
        using Ch = C;
        using Tr = std::char_traits<C>;
        using Sv = std::basic_string_view<C>;
    };

    template <class C, size_t N>
    struct string_traits<C[N]> {
        using Ch = C;
        using Sv = std::basic_string_view<C>;
    };

    template<class S>
    using s_v_t = typename string_traits<std::remove_cvref_t<S>>::Sv;

    namespace detail {
        template <class Sv>
        Sv remainderSv(Sv s, Sv prefix)
        {
            if (s.length() <= prefix.length()
                    || !s.starts_with(prefix))
                return {};
            return s.substr(prefix.length(), s.length() - prefix.length());
        }
    }

    /// @brief remainderSv
    ///    Same for prefix only
    template <class A>
    inline auto remainderSv(const A& s, s_v_t<A> prefix) -> s_v_t<A>
        { return detail::remainderSv<s_v_t<A>>(s, prefix); }

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question