diff --git a/.github/workflows/asciidoctor-ghpages.yml b/.github/workflows/asciidoctor-ghpages.yml index 995e298..8bcae2c 100644 --- a/.github/workflows/asciidoctor-ghpages.yml +++ b/.github/workflows/asciidoctor-ghpages.yml @@ -42,7 +42,7 @@ jobs: - name: Install Mermaid run: | - sudo npm install -g @mermaid-js/mermaid-cli@11.2.1 + npm install -g @mermaid-js/mermaid-cli@11.4.2 npx puppeteer browsers install chrome-headless-shell - name: Install asciidoctor diff --git a/include/stdx/ct_format.hpp b/include/stdx/ct_format.hpp index a7641f3..9744ed8 100644 --- a/include/stdx/ct_format.hpp +++ b/include/stdx/ct_format.hpp @@ -31,6 +31,9 @@ struct fmt::formatter> : fmt::formatter { namespace stdx { inline namespace v1 { template struct format_result { + CONSTEVAL static auto + ct_string_convertible() -> std::bool_constant; + [[no_unique_address]] Str str; [[no_unique_address]] Args args{}; diff --git a/include/stdx/ct_string.hpp b/include/stdx/ct_string.hpp index 0efd5f2..79dc1f9 100644 --- a/include/stdx/ct_string.hpp +++ b/include/stdx/ct_string.hpp @@ -3,15 +3,29 @@ #if __cplusplus >= 202002L #include +#include #include #include +#include #include #include +#include #include namespace stdx { inline namespace v1 { + +template struct ct_string; + +namespace detail { +template +concept format_convertible = requires(T t) { + { T::ct_string_convertible() } -> std::same_as; + { ct_string{t.str.value} }; +}; +} // namespace detail + template struct ct_string { CONSTEVAL ct_string() = default; @@ -23,6 +37,10 @@ template struct ct_string { } } + template + // NOLINTNEXTLINE(google-explicit-constructor) + CONSTEVAL explicit(false) ct_string(T t) : ct_string(t.str.value) {} + CONSTEVAL explicit(true) ct_string(char const *str, std::size_t sz) { for (auto i = std::size_t{}; i < sz; ++i) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-*) @@ -59,6 +77,9 @@ template struct ct_string { std::array value{}; }; +template +ct_string(T) -> ct_string().str.value)::capacity()>; + template [[nodiscard]] constexpr auto operator==(ct_string const &lhs, ct_string const &rhs) -> bool { @@ -116,6 +137,7 @@ operator+(ct_string const &lhs, } template struct cts_t { + using value_type = decltype(S); constexpr static auto value = S; }; diff --git a/test/ct_format.cpp b/test/ct_format.cpp index b59cca8..9e875fc 100644 --- a/test/ct_format.cpp +++ b/test/ct_format.cpp @@ -142,6 +142,23 @@ TEST_CASE("format a format result", "[ct_format]") { stdx::make_tuple(2022)}); } +namespace { +template constexpr auto conversion_success = true; +} // namespace + +TEST_CASE("empty format_result can implicitly convert to ct_string", + "[ct_format]") { + using namespace std::string_view_literals; + static_assert( + stdx::detail::format_convertible())>); + static_assert(stdx::detail::format_convertible< + decltype(stdx::ct_format<"Hello {}">("world"_ctst))>); + static_assert(not stdx::detail::format_convertible< + decltype(stdx::ct_format<"Hello {}">(42))>); + + static_assert(conversion_success()>); +} + namespace { template struct string_constant { private: